Arduino - Basic Authentication

Hello,

I still a newbie in Arduino World, so I'm looking for some advice.

I made a server to automate my house using livolo switches and some other stuff, using HTML files from the SD Card using a Arduino UNO, and an W5100 Ethernet Shield... The code is already working fine (at least I think it is), but I'm having troubles trying to implement a Basic Authentication on the server, just to avoid people that may find the server by mistake / miss typing.

I'm trying to mix the code I already made (above), with the Webduino library (GitHub - sirleech/Webduino: Arduino WebServer library) and the Web_Authentication example , but my programming skills aren't the best, and I can't figure it out.

Thanks in advance.

Any suggestions or improvements are welcome.

Have a look at my Arduino home automation website at www.2wg.co.nz.

Anyone can access and browse the wide range of functionality. But the only way to change or control anything from a remote internet location is to login using a password.

If you only want to control your system on your local LAN and at remote locations with known IP addresses you could use the IP addresses for authentication. If you want to control the system from anywhere and any IP address you need some sort of password control.

If you don't want to enter the password on every form that contains an action that you want to execute you may need to implement session cookies. My application assigns and uses session cookies - after I have logged in with the correct password I get ten minutes to do what I need before the session cookie times out.

This is not easy stuff. Download and review the file http://www.2wg.co.nz/PUBLIC/COOKIES.TXT/ to see how I implemented and use session cookies for application authentication control.

Cheers

Catweazle NZ

You might also like to look at www.pfod.com.au
which provides a very simple means of controlling things from your Android mobile via wifi/ethernet with 128bit security.
One of the advantages of this 128bit security is that it is very light weight, using about 2100 bytes of program space and about 400 bytes RAM (including the pfod message parser)

see A Simple WiFi/Arduino pfodDevice™ with 128 bit security for a full tutorial.
A password generator which writes the password to a QR image is also available.

Lots of other examples at www.pfod.com.au. Some for complete beginners.

The 128bit security is explained in detail here
SipHash Secure Challenge and Response for micro-devices (AVR / Arduino) and uses a sipHash for each message to prevent un-authorized connection or man in the middle attacks. The messages themselves remain in plain text which helps with debugging.

The 128bit security can be added to any pfodDevice connecting via a host name or ip just by changing the pfod parser library used.

There is a pfodDesigner which lets you design custom menus to turn Arduino outputs on and off.
see pfodDesignerV3 <a href="https://play.google.com/store/apps/details?id=au.com.forward.pfodDesignerV2" TARGET="_blank"> <img alt="pfodDesigner on Google Play"src="en_app_rgb_wo_45.png" /></a> Android / Arduino menus made Simple<br>No Programming Required
Here is an example menu designed using pfodDesigner. The buttons are connected to D4 and D5. You set the connections as part of the design, no coding required.

Hello CatweazleNZ,

Thanks for your suggestion, I will look deep into it.
As you said it looks really hard stuff.

Hello drmpf,

Thanks for your suggestion too.
But in this case I don’t want to restrict acess only to cell phones, and my site design is already done and I liked the result.

Acctually I was thinking in a simple sollution, I was trying to do it this way, but when I upload this code the Serial Monitor goes crazy printing a bunch of caracters and the web server doesn’t even start.

#define WEBDUINO_AUTH_REALM "Automação Residencial"
#include <SPI.h>
#include <Ethernet.h>
#include <WebServer.h>
#include <EthernetUdp.h>
#include <SD.h>
#include <livolo.h>

#define REQ_BUF_SZ   20 // size of buffer used to capture HTTP requests
EthernetUDP Udp;
Livolo livolo(8); // transmitter connected to pin #8

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte TargetMac[] = {0x60, 0xA4, 0x4C, 0x63, 0x61, 0xD6};  // PC's MAC address
IPAddress ip(192, 168, 1, 5); // IP address, may need to change depending on network
byte broadcast[] = {192, 168, 1, 255};    // Broadcast IP address
EthernetServer server(80); // create a server at port 80
File webFile; // handle to files on SD card
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0; // index into HTTP_req buffer
WebServer webserver("", 80);

void Login(WebServer &server, WebServer::ConnectionType type, char *, bool) {
  if (webserver.checkCredentials("YWRtaW46YWRtaW4=")) {
    webserver.httpSuccess();
    if (type != WebServer::HEAD) {
      P(helloMsg) = "<h1>Hello Admin</h1>";
      webserver.printP(helloMsg);
    }
    StartWeb();
  }
  else {
    webserver.httpUnauthorized();
  }
}
void setup(){
  pinMode(10, OUTPUT); // disable Ethernet chip
  digitalWrite(10, HIGH);
  Serial.begin(9600); // for debugging
  Serial.println("Initializing SD card..."); // initialize SD card
  if (!SD.begin(4)) {
    Serial.println("ERROR - SD card initialization failed!"); // initialization failed
    return; 
  }
  Serial.println("SUCCESS - SD card initialized.");
  if (!SD.exists("index.htm")) { // check for index.htm file
    Serial.println("ERROR - Can't find index.htm file!");
    return;  // can't find index file
  }
  Serial.println("SUCCESS - Found index.htm file.");
  Ethernet.begin(mac, ip); // initialize Ethernet device
  server.begin(); // start to listen for clients
  webserver.setDefaultCommand(&Login);
  webserver.begin();
  Udp.begin(9);
}
void loop(){
  char buff[64];
  int len = 64;
  webserver.processConnection(buff, &len);
}
void StartWeb() {
  EthernetClient client = server.available();  // try to get client
  if (client) {  // got client?
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) { // client data available to read
        char c = client.read(); // read 1 byte (character) from client
        Serial.write(c); // print HTTP request character to serial monitor
        if (req_index < (REQ_BUF_SZ - 1)) {
          HTTP_req[req_index] = c; // save HTTP request character
          req_index++;
        }
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connnection: close");
          client.println();
          // if GET request
          if (StrContains(HTTP_req, "GET / ") || StrContains(HTTP_req, "index.htm")) {
            webFile = SD.open("index.htm"); // open web page file
          }
          else if (StrContains(HTTP_req, "1Andar.htm")) {
            webFile = SD.open("1Andar.htm"); // open web page file
          }
          else if (StrContains(HTTP_req, "2Andar.htm")) {
            webFile = SD.open("2Andar.htm"); // open web page file
          }
          else if (StrContains(HTTP_req, "3Andar.htm")) {
            webFile = SD.open("3Andar.htm"); // open web page file
          }
          // if POST request
          if (StrContains(HTTP_req, "POST /")){
            String POST = "";
            while(client.available()){
              c = client.read();
              POST += c;
            } 
            if(StrContains(HTTP_req, "/livolo")) {
              String controlvalue = POST.substring(0, POST.indexOf('&'));
              String buttonvalue = POST.substring(POST.indexOf('&') + 1, POST.length());
              String control = controlvalue.substring(controlvalue.indexOf('=') + 1, controlvalue.length());
              String button = buttonvalue.substring(buttonvalue.indexOf('=') + 1, buttonvalue.length());
              livolo.sendButton(control.toInt(), button.toInt());
            }
            else if (POST != "") {
              String cmdname = POST.substring(0, POST.indexOf('&'));
              String cmdvalue = POST.substring(POST.indexOf('&') + 1, POST.length());
              String name = cmdname.substring(cmdname.indexOf('=') + 1, cmdname.length());
              String value = cmdvalue.substring(cmdvalue.indexOf('=') + 1, cmdvalue.length());
              if (name == "Garagem") {
                //command
              }
              if (name == "Portao") {
                //command
              }
              if (name == "Alarme") {
                //command
              }
              if (name == "Cobertura") {
                //command
              }
              if (name == "PC" && value.toInt() == 1) {
                  WOL(TargetMac);
              }
            }
            XML_response(client); // send XML file 
          }
          if (webFile) { // send web page to client
            while(webFile.available()) {
              client.write(webFile.read());
            }
            webFile.close();
          }
          req_index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1); // give the web browser time to receive the data
    client.stop(); // close the connection
  }
}
void StrClear(char *str, char length){
  for (int i = 0; i < length; i++) {
    str[i] = 0;
  }
}
void XML_response(EthernetClient cl) { // send the XML file
  cl.print("<?xml version = \"1.0\"?>");
  cl.print("<response>");
  cl.print("Ok");
  cl.print("</response>");
}
void WOL(byte mac[]) {
  byte preamble[] = {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF    };
  int i = 0;
  Udp.beginPacket(broadcast, 9);
  Udp.write(preamble, sizeof preamble);
  while (i<16){
    Udp.write(TargetMac, sizeof TargetMac);
    i++;
  }
  Udp.endPacket();
}
char StrContains(char *str, char *sfind){
  char found = 0;
  char index = 0;
  char len;
  len = strlen(str);
  if (strlen(sfind) > len) {
    return 0;
  }
  while (index < len) {
    if (str[index] == sfind[found]) {
      found++;
      if (strlen(sfind) == found) {
        return 1;
      }
    }
    else {
      found = 0;
    }
    index++;
  }
  return 0;
}