add more testing for auth middleware
diff --git a/crow/include/crow/app.h b/crow/include/crow/app.h
index 40b759c..9162352 100644
--- a/crow/include/crow/app.h
+++ b/crow/include/crow/app.h
@@ -37,6 +37,7 @@
   using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
 #endif
   Crow() {}
+  ~Crow() { this->stop(); }
 
   template <typename Adaptor>
   void handle_upgrade(const request& req, response& res, Adaptor&& adaptor) {
@@ -98,11 +99,15 @@
   void stop() {
 #ifdef CROW_ENABLE_SSL
     if (use_ssl_) {
-      ssl_server_->stop();
+      if (ssl_server_ != nullptr) {
+        ssl_server_->stop();
+      }
     } else
 #endif
     {
-      server_->stop();
+      if (server_ != nullptr) {
+        server_->stop();
+      }
     }
   }
 
diff --git a/src/token_authorization_middleware.cpp b/src/token_authorization_middleware.cpp
index 91feaf1..bf5efe1 100644
--- a/src/token_authorization_middleware.cpp
+++ b/src/token_authorization_middleware.cpp
@@ -24,6 +24,11 @@
     res.end();
   };
 
+  auto return_bad_request = [&req, &res]() {
+    res.code = 400;
+    res.end();
+  };
+
   LOG(DEBUG) << "Token Auth Got route " << req.url;
 
   if (req.url == "/" || boost::starts_with(req.url, "/static/")) {
@@ -43,7 +48,11 @@
     } else {
       auto login_credentials = crow::json::load(req.body);
       if (!login_credentials) {
-        return_unauthorized();
+        return_bad_request();
+        return;
+      }
+      if (!login_credentials.has("username") || !login_credentials.has("password")){
+        return_bad_request();
         return;
       }
       auto username = login_credentials["username"].s();
diff --git a/src/token_authorization_middleware_test.cpp b/src/token_authorization_middleware_test.cpp
index 9b2bcc8..9f8e626 100644
--- a/src/token_authorization_middleware_test.cpp
+++ b/src/token_authorization_middleware_test.cpp
@@ -5,73 +5,232 @@
 using namespace crow;
 using namespace std;
 
-// Tests that Base64 basic strings work
-TEST(TokenAuthentication, TestBasicReject)
-{
-    App<crow::TokenAuthorizationMiddleware> app;
-    decltype(app)::server_t server(&app, "127.0.0.1", 45451);
-    CROW_ROUTE(app, "/")([]()
-    {
-        return 200;
-    });
-    auto _ = async(launch::async, [&]{server.run();});
-    asio::io_service is;
-    std::string sendmsg;
+// Tests that static urls are correctly passed
+TEST(TokenAuthentication, TestBasicReject) {
+  App<crow::TokenAuthorizationMiddleware> app;
+  decltype(app)::server_t server(&app, "127.0.0.1", 45451);
+  CROW_ROUTE(app, "/")([]() { return 200; });
+  auto _ = async(launch::async, [&] { server.run(); });
+  asio::io_service is;
+  std::string sendmsg;
 
-    static char buf[2048];
+  static char buf[2048];
 
-    // Homepage should be passed with no credentials
-    sendmsg = "GET /\r\n\r\n";
-    {
-        asio::ip::tcp::socket c(is);
-        c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451));
-        c.send(asio::buffer(sendmsg));
-        auto received_count = c.receive(asio::buffer(buf, 2048));
-        c.close();
-        ASSERT_EQ("200", std::string(buf + 9, buf + 12));
-    }
-
-     // static should be passed with no credentials
-    sendmsg = "GET /static/index.html\r\n\r\n";
-    {
-        asio::ip::tcp::socket c(is);
-        c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451));
-        c.send(asio::buffer(sendmsg));
-        c.receive(asio::buffer(buf, 2048));
-        c.close();
-        ASSERT_EQ("404", std::string(buf + 9, buf + 12));
-    }
-
-    
-   server.stop();
-   
-}
-
-
-// Tests that Base64 basic strings work
-TEST(TokenAuthentication, TestSuccessfulLogin)
-{
-    App<crow::TokenAuthorizationMiddleware> app;
-    app.bindaddr("127.0.0.1").port(45451);
-    CROW_ROUTE(app, "/")([]()
-    {
-        return 200;
-    });
-    auto _ = async(launch::async, [&]{app.run();});
-
-    asio::io_service is;
-    static char buf[2048];
-    //ASSERT_NO_THROW(
-    // Other resources should not be passed
-    std::string sendmsg = "GET /foo\r\n\r\n";
+  // Homepage should be passed with no credentials
+  sendmsg = "GET /\r\n\r\n";
+  {
     asio::ip::tcp::socket c(is);
-    c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451));
+    c.connect(asio::ip::tcp::endpoint(
+        asio::ip::address::from_string("127.0.0.1"), 45451));
     c.send(asio::buffer(sendmsg));
     auto received_count = c.receive(asio::buffer(buf, 2048));
     c.close();
-    ASSERT_EQ("401", std::string(buf + 9, buf + 12));
-    
-    app.stop();
-    raise;
-   
+    EXPECT_EQ("200", std::string(buf + 9, buf + 12));
+  }
+
+  // static should be passed with no credentials
+  sendmsg = "GET /static/index.html\r\n\r\n";
+  {
+    asio::ip::tcp::socket c(is);
+    c.connect(asio::ip::tcp::endpoint(
+        asio::ip::address::from_string("127.0.0.1"), 45451));
+    c.send(asio::buffer(sendmsg));
+    c.receive(asio::buffer(buf, 2048));
+    c.close();
+    EXPECT_EQ("404", std::string(buf + 9, buf + 12));
+  }
+
+  server.stop();
+}
+
+// Tests that Base64 basic strings work
+TEST(TokenAuthentication, TestRejectedResource) {
+  App<crow::TokenAuthorizationMiddleware> app;
+  app.bindaddr("127.0.0.1").port(45451);
+  CROW_ROUTE(app, "/")([]() { return 200; });
+  auto _ = async(launch::async, [&] { app.run(); });
+
+  asio::io_service is;
+  static char buf[2048];
+
+  // Other resources should not be passed
+  std::string sendmsg = "GET /foo\r\n\r\n";
+  asio::ip::tcp::socket c(is);
+  for (int i = 0; i < 200; i++) {
+    try {
+      c.connect(asio::ip::tcp::endpoint(
+          asio::ip::address::from_string("127.0.0.1"), 45451));
+    } catch (std::exception e) {
+      // do nothing
+    }
+  }
+  c.send(asio::buffer(sendmsg));
+  auto received_count = c.receive(asio::buffer(buf, 2048));
+  c.close();
+  EXPECT_EQ("401", std::string(buf + 9, buf + 12));
+
+  app.stop();
+}
+
+// Tests that Base64 basic strings work
+TEST(TokenAuthentication, TestGetLoginUrl) {
+  App<crow::TokenAuthorizationMiddleware> app;
+  app.bindaddr("127.0.0.1").port(45451);
+  CROW_ROUTE(app, "/")([]() { return 200; });
+  auto _ = async(launch::async, [&] { app.run(); });
+
+  asio::io_service is;
+  static char buf[2048];
+
+  // Other resources should not be passed
+  std::string sendmsg = "GET /login\r\n\r\n";
+  asio::ip::tcp::socket c(is);
+  for (int i = 0; i < 200; i++) {
+    try {
+      c.connect(asio::ip::tcp::endpoint(
+          asio::ip::address::from_string("127.0.0.1"), 45451));
+    } catch (std::exception e) {
+      // do nothing
+    }
+  }
+  c.send(asio::buffer(sendmsg));
+  auto received_count = c.receive(asio::buffer(buf, 2048));
+  c.close();
+  EXPECT_EQ("401", std::string(buf + 9, buf + 12));
+
+  app.stop();
+}
+
+// Tests boundary conditions on login
+TEST(TokenAuthentication, TestPostBadLoginUrl) {
+  App<crow::TokenAuthorizationMiddleware> app;
+  app.bindaddr("127.0.0.1").port(45451);
+  CROW_ROUTE(app, "/")([]() { return 200; });
+  auto _ = async(launch::async, [&] { app.run(); });
+
+  asio::io_service is;
+  std::array<char, 2048> buf;
+  std::string sendmsg;
+
+  auto send_to_localhost = [&is, &buf](std::string sendmsg) {
+    asio::ip::tcp::socket c(is);
+    c.connect(asio::ip::tcp::endpoint(
+        asio::ip::address::from_string("127.0.0.1"), 45451));
+    c.send(asio::buffer(sendmsg));
+    auto received_count = c.receive(asio::buffer(buf));
+    c.close();
+  };
+
+  {
+    // Retry a couple of times waiting for the server to come up
+    asio::ip::tcp::socket c(is);
+    for (int i = 0; i < 200; i++) {
+      try {
+        c.connect(asio::ip::tcp::endpoint(
+            asio::ip::address::from_string("127.0.0.1"), 45451));
+        c.close();
+        break;
+      } catch (std::exception e) {
+        // do nothing.  We expect this to fail while the server is starting up
+      }
+    }
+  }
+
+  // Test blank login credentials
+  sendmsg = "POST /login\r\nContent-Length:0\r\n\r\n\r\n";
+  {
+    send_to_localhost(sendmsg);
+    auto return_code = std::string(&buf[9], &buf[12]);
+    EXPECT_EQ("400", return_code);
+  }
+
+  // Test wrong login credentials
+  sendmsg =
+      "POST /login\r\nContent-Length:38\r\n\r\n{\"username\": \"foo\", "
+      "\"password\": \"bar\"}\r\n";
+  {
+    send_to_localhost(sendmsg);
+    auto return_code = std::string(&buf[9], &buf[12]);
+    EXPECT_EQ("401", return_code);
+    // TODO(ed) need to test more here.  Response string?
+  }
+
+  // Test only sending a username
+  sendmsg =
+      "POST /login\r\nContent-Length:19\r\n\r\n{\"username\": \"foo\"}\r\n";
+  {
+    send_to_localhost(sendmsg);
+    auto return_code = std::string(&buf[9], &buf[12]);
+    EXPECT_EQ("400", return_code);
+  }
+
+  // Test only sending a password
+  sendmsg =
+      "POST /login\r\nContent-Length:19\r\n\r\n{\"password\": \"foo\"}\r\n";
+  {
+    send_to_localhost(sendmsg);
+    auto return_code = std::string(&buf[9], &buf[12]);
+    EXPECT_EQ("400", return_code);
+  }
+
+  app.stop();
+}
+
+// Tests boundary conditions on login
+TEST(TokenAuthentication, TestSuccessfulLogin) {
+  App<crow::TokenAuthorizationMiddleware> app;
+  app.bindaddr("127.0.0.1").port(45451);
+  CROW_ROUTE(app, "/")([]() { return 200; });
+  auto _ = async(launch::async, [&] { app.run(); });
+
+  asio::io_service is;
+  std::array<char, 2048> buf;
+  std::string sendmsg;
+
+  auto send_to_localhost = [&is, &buf](std::string sendmsg) {
+    asio::ip::tcp::socket c(is);
+    c.connect(asio::ip::tcp::endpoint(
+        asio::ip::address::from_string("127.0.0.1"), 45451));
+    c.send(asio::buffer(sendmsg));
+    auto received_count = c.receive(asio::buffer(buf));
+    c.close();
+  };
+
+  {
+    // Retry a couple of times waiting for the server to come up
+    asio::ip::tcp::socket c(is);
+    for (int i = 0; i < 200; i++) {
+      try {
+        c.connect(asio::ip::tcp::endpoint(
+            asio::ip::address::from_string("127.0.0.1"), 45451));
+        c.close();
+        break;
+      } catch (std::exception e) {
+        // do nothing.  We expect this to fail while the server is starting up
+      }
+    }
+  }
+
+  // Test correct login credentials
+  sendmsg =
+      "POST /login\r\nContent-Length:40\r\n\r\n{\"username\": \"dude\", "
+      "\"password\": \"dude\"}\r\n";
+  {
+    send_to_localhost(sendmsg);
+    auto return_code = std::string(&buf[9], &buf[12]);
+    EXPECT_EQ("200", return_code);
+  }
+
+
+  // Try to use those login credentials to access a resource
+  sendmsg =
+      "GET /\r\nAuthorization: token\r\n\r\n{\"username\": \"dude\", "
+      "\"password\": \"dude\"}\r\n";
+  {
+    send_to_localhost(sendmsg);
+    auto return_code = std::string(&buf[9], &buf[12]);
+    EXPECT_EQ("200", return_code);
+  }
+
+  app.stop();
 }
\ No newline at end of file