Project Overview

While some plug and play solutions exist such as the Liftmaster 828LM , I wanted to make my own out of curiosity.





The project consists of two components, both of which are entirely open source:

An Android application which posts commands to a web service. The Android application retrieves an authorization token from Google and sends it along with the requested command.

https://github.com/ryanfx/GarageAndroid

The web service which listens for commands and credentials. These credentials are posted to Google to verify they are authentic. Once the user is verified, the command is executed.

https://github.com/ryanfx/GarageWebService

Run Tomcat on their Raspberry Pi

Authenticate users with Google's OAuth 2 (both getting the token and authenticating the token)

Interact with the GPIO pins of the Raspberry Pi directly in Java

See how a basic Service to Activity (interaction / communication) model can look like in Android. I find this to be one of the most common questions asked by new developers

Demonstration:

This is a quick video of the whole project in use. Note the status of the door is stated on the home screen of the application so there is never any doubt whether it is open or closed!





Hardware

Raspberry Pi Model B - It can act as the web service and physically interface with the garage door all in one device (rather than purchasing something like an Arduino, which would need a more powerful computer sitting in front of it to run the web service). Less is more.

Edimax EW-7811Un USB Wi-Fi N Dongle - Since I don't have CAT6 run out to my garage door opener (yet), I had to accept using Wi-Fi which I generally avoid at all costs. The chipset in this dongle (RTL8188CUS) is compatible right out of the box with the Raspberry Pi.

Magnetic Switch - This is to determine whether the garage is opened or closed. This particular switch is fantastic for one reason; depending on which contact points you hook up to, it can be made either normally open or normally closed.

Sainsmart Relay Module - Great little board that has relay isolation components already built into it. Separates the power supply from the signal with an optocoupler which protects your other components when the coil's magnetic field collapses.

Resistors - Miscellaneous resistors. Supplied link is a great pack that gives you a little bit of everything for home projects.

Wiring of your choice.



Design requirements

Control (toggle) the garage remotely, whether 5 feet away, or 5 countries away

Check the state of the garage door, without needing to toggle / close it

Do so from within an Android application

Use Google as the application's authenticator



Take advantage of Android's AccountManager

Be accessible via HTTP so it could be extended to any platform in the future such as iPhone, iPad, or a simple web browser

Run HTTPS so eavesdropping / replay attacks would not be possible



Use an unsigned TLS certificate. There is no need to pay for one if you are the developer!

WAF needs to be high.

Low cost



Must not affect normal operation of the door

No pre-built solutions

Rarely demonstratively secure



Not extensible



Not fun =P

Web Service

The web service is responsible for listening for requests over the network. This performs the following actions upon receiving a request:

Authenticates the request with Google OAuth 2.0 with an subclass of RealmBase, GoogleRealm. Authorizes the user with a local file containing a line delineated list of valid users If there was a successful authentication and authorization, perform the required action, namely: Toggle the garage

Get the state of the garage Libraries Used

Pi4J - Java bindings which allows interaction with the GPIO pins on the Raspberry Pi. Being Tomcat is the web server, Pi4J was a perfect complement. json-simple - Java library which parses and extracts JSON messages. Security





In this application, the oauth2:https://www.googleapis.com/auth/userinfo.email which, when posted to Google, allows the verifier to view the email address of the account that the authentication token is associated with.



I originally did not have this shared password in place but I soon realized that there was a security vulnerability in the application. Any service that you authenticate with using your Google account could post its own authorization token to your garage door opener and open your garage. In computer security, this is called the



Once the user's request is authenticated it is then checked for authorization against a line delineated local file which has a list of email addresses allowed to interact with the application. If that email exists, the proper



Garage Interface The application is protected with an implementation of a Realm . This implementation is dubbed "GoogleRealm" and validates Google authorization tokens, as well as validates that the returned email account exists in a local file. When Tomcat handles an HTTP request for a protected resource (defined in web.xml), it calls the overridden authenticate method inside of GoogleRealm method with two Strings. These strings are passed in by the defined implementation of Authenticator , also defined inside web.xml. An Authenticator's job in the scope of Tomcat is to take a Request and send the passed credentials to the defined Realm. Making a custom Authenticator allows one to receive credentials from a request by any means. In other words, it abstracts how credentials are retrieved in the request from how they are authenticated.In this application, the BasicAuthenticator is used to retrieve credentials. You may have been able to guess that BasicAuthenticator retrieves the username and password from HTTP basic access authentication . The username field contains the Google authorization token and the password field contains a shared secret among all users. The authorization token is requested with the scopewhich, when posted to Google, allows the verifier to view the email address of the account that the authentication token is associated with.I originally did not have this shared password in place but I soon realized that there was a security vulnerability in the application. Any service that you authenticate with using your Google account could post its own authorization token to your garage door opener and open your garage. In computer security, this is called the confused deputy problem . This can be mitigated by requiring an additional secret with all authorized users. With a shared secret, third party sites need an additional piece of information that only authorized users posses.Once the user's request is authenticated it is then checked for authorization against a line delineated local file which has a list of email addresses allowed to interact with the application. If that email exists, the proper Principal is then added to the request session and passed to servlet routing.

Toggling the garage

The garage door was fairly straight forward to interact with physically. I had a wall mounted control which toggles the garage door when two wires are shorted together (this is the behavior of most any door).



When this module is activated, the garage is toggled. This module is controlled via the following wires: ( Note - make sure you know which revision of the Raspberry Pi you have as their pins have changed!)



5V - Pin 02 on the Raspberry Pi diagram below (upper right pin) to label G on the relay diagram. This powers the relay coil.





3.3V - Pin 17 (fifth from the bottom, left row) to label F. This provides 3.3V as a signal current to the relay.





0V - Pin 25 to label E. This grounds the 5V supply. Note that the 5V and 0V are isolated via an optocoupler from the 3.3V connection(The schematic can be found here.)





GPIO - Pin 11 (GPIO 17) to label B. This is going to be configured as an OUTPUT pin, and set LOW , which will activate the relay.

pin, and set , which will activate the relay.



The two top most screw-down relay holes (in the upper left) are what will be connected to each other when the relay triggers. These two wires will need to be run to your garage door in a manufacturer / model dependent fashion. From http://elinux.org/Rpi_Low-level_peripherals

Notated relay board Checking the garage state

This was accomplished with the magnetic switch listed above. One half of the switch is connected to the swinging door, the other half is attached to the door frame. In this case half of it was attached to the wall above the garage door, and half of it was attached to the garage door itself. When the garage door is closed, these two halves are within about a 1/4 inch of each other.



Make a wire with an inline 1k ohm resistor (to prevent accidentally blowing out a GPIO pin).



3.3V - Connect this wire from Pin 1 on the Raspberry Pi and connect it to one side of the magnetic switch mentioned above (red, or white wire in diagram below)





Connect a wire from the opposite side of the magnetic switch and run it to pin 12 (GPIO 18).





When the door is closed, this circuit should be closed. This is the magnetic switch. The front side (closest in this picture) is attached to the moving door, the rear side is screwed into the wall. When they come within about 1/4 inch of each other, it toggles.







Sorry for the mediocre picture... it's mounted on top of the opener.

Android Application





Architecture: The architecture of the application is very simple. Clicking an action button in the UI triggers an IntentService to run. These IntentService(s) are run in the background on a worker thread already, so we don't need to worry about spawning off threads on our own. When the Service is completed, it fires off a broadcast. If the main Activity is active at this point, a Toast is generated for the user which states what the result of their action was.





Overview:













There are three interaction points in the application that this token is used for: The controller for this application is written for the Android platform. This could have been a web application but I wanted to use the AccoutManager on Android so the setup was as seamless as possible to any end user (no need to enter account information). The first time a user account is selected and an action button is clicked, an authorization prompt pops up for the user. This allows the application to get a token which can prove the account's identity.There are three interaction points in the application that this token is used for:

Toggle the garage (actuate the relay which in turns activates the door)

Close the the garage (toggles the garage if it is not in a closed state)

Display the status of the garage (open / closed)





Security:





UI: Main screen Configuration Screen (accessible by hitting menu button)

The security of the Android application lies in its use of HTTPS. I did not want to create my own domain and pay for a signed TLS certificate, so instead, I made an SSLSocketFactory factory ( GarageSSLSocketFactory ). This is described in good detail here . What this does is initialize the application's SSLContext to use your own default key store for acceptable certificates. This includes your own self-signed certificates and allows you to have secure communication without the need for paying for a signed certificate, or doing something really, really, bad . All you need is a dynamic DNS domain, assuming you do not have a reserved WAN IP address.

Configuration

Download the GarageWebService and GarageAndroid from Github. (If you've downloaded it in the past, make sure you update your repository to fix a classpath error. On a spare computer (other than the RPi) install Eclipse for Java Developers Click Help -> Install new Software Select Work with Kepler - http://download.eclipse.org/releases/kepler Install Eclipse Java EE Developer Tools, Eclipse Java Web Developer Tools, JST Server Adapters, JST Server Adapters Extensions, then restart Eclipse New->Other->Web->Dynamic Web Project -- Name it GarageWebService Select target runtime if it already exists, or click new runtime if you don't have one. Click Apache Tomcat v7.0 - Check create new local server Click download and install (If you don't already have it) Close eclipse copy src + WebContent from downloaded GarageWebService and override the current src + WebContent in the workspace project (probably {homedir}/workspace/GarageWebService) Reopen eclipse, right click in the navigator pane on the left and click refresh Open GoogleRealm.java and change the password if desired. This password protects your garage door from being used from another service that has some permission on your Google account (such as stackoverflow) Highlight the files GoogleRealm.java, GoogleUtil.java, and UserDAO.java Right click on one of the highlighted files-> export -> Java -> JAR file and name it GoogleAuth.jar Now right click on the project itself, export -> Web -> war file and name it GarageDoor.war (important the name + case is exactly this) Install the Raspian distribution on your RPi, then enable SSH for terminal access. We do not need a graphical interface Transfer GoogleAuth.war to the Rpi sudo apt-get update and sudo apt-get upgrade sudo apt-get install tomcat7 tomcat7-admin edit /etc/default/tomcat7 and change the following two variables TOMCAT7_USER=root JAVA_HOME=/usr/lib/jvm/jdk-7-oracle-armhf Change to a directory for downloading files (we will now be installing wiringPi) git clone git://git.drogon.net/wiringPi cd wiringPi git pull origin sudo ./build Now we'll add ourselves as a valid tomcat user sudo nano /etc/tomcat7/tomcat-users.xml Add the following line, right above the last line, </tomcat-users> <user username="ryanfx" password="asecretpassword" roles="manager-gui"/> Replace ryanfx and asecretpassword with whatever you'd like Generating an SSL certificate We will generate a certificate using RSA and name the store garagessl keytool -genkey -alias garage -keyalg RSA -keystore garagessl For the question "w hat is your first and last name?" enter the external IP address or dyn-dns name that your RPi will be using eg. www.mydyndnsname.com Everything else can be blank, but enter y when it confirms that all the information is correct. Let it generate a new certificate for a few minutes, then hit enter when it asks you for a new password Change permissions and move it to someplace that tomcat can read it sudo chown root:tomcat7 garagessl sudo mv garagessl /etc/tomcat7 Configure Tomcat to read the certificate sudo nano /etc/tomcat7/server.xml Copy the following below the connector element already active running on port 8080, and comment out the one running on port 8080

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"

maxThreads="150" scheme="https" secure="true"

clientAuth="false" sslProtocol="TLS"

keystoreFile="/etc/tomcat7/garagessl"

keystorePass="thepasswordyouused" /> We'll copy the GarageAuth jar to the Java library folder sudo mv GoogleAuth.jar /usr/share/java/ Find the json simple jar inside the web service package you downloaded and move it as well. We need to do this because security realm's use Tomcat's (Catalina's) classloader, not your webapp's. sudo mv json_simple-1.1.jar /usr/share/java/ Create softlinks so tomcat has access to them cd /usr/share/tomcat7/lib/ sudo ln -s ../../java/GoogleAuth.jar . sudo ln -s ../../java/json_simple-1.1.jar . Add users that will be able to authorize with your new service sudo nano /root/garage_users Add a single line to the file, whatever the gmail address is that you will be authenticating with. Restart Tomcat sudo /etc/init.d/tomcat7 restart Open a browser on the Eclipse machine and go to https://192.168.11.30:8443/ replacing the IP address with whatever IP address your Rpi has pulled. You should get a "certificate untrusted" error. If you've reached this point, everything is good! Upload the GarageDoor.war to the raspberry pi's Tomcat. In this example, visit https://192.168.11.30:8443/manager/html Click start to start it Now we will get the public certificate the server is issuing and store it in PEM format. Replace the IP address to whatever the RPi has. echo | openssl s_client -connect 192.168.11.30:8443 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem You now have the PEM encoded certificate of your server. We will now download bouncy castle jars to generate a keystore (do not download past version 146 - Android will not play nice with anything newer) wget http://www.bouncycastle.org/download/bcprov-jdk15on-146.jar We will now generate the keystore (enter a password when prompted to protect your keystore and enter yes to trust this certificate) keytool -import -v -trustcacerts -alias 0 -file <(openssl x509 -in ./mycert.pem) -keystore mystore.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ./bcprov-jdk15on-146.jar Copy mystore.bks to the machine which has eclipse Open eclipse Install android ADT (http://developer.android.com/sdk/installing/installing-adt.html) Import -> Android -> Existing Android Code Into Workspace Create a new folder called raw inside of the res folder Move your mystore.bks file into this new folder Change the password in GarageSSLSocketFactory.java to reflect the password used during the keytool command Right click the Project -> export -> Android -> Export Android Application Install the application to your phone Open the app, go to settings, fill in host / port / account information Fill in the server password (the one you wrote in GoogleRealm.java) You're done!

A few months ago I had left for a business trip and couldn't remember if I had closed the garage door. Nearly all of us have done this at one point in our lives. I promised myself this would never happen again, and a new project was spawned!I will be giving an overview of the project, but it is by no means a step-by-step tutorial. There have been similar projects online, but I couldn't find any with detailed code on both sides (client + server). This should be a good reference for anyone who wants to do things like: