Server Login (HTTP Headers Handle)

Hello everyone,

I am trying to make a webserver with a authorization login. I start with the webserver example to understand exactly what I'm doing.

I sent the "HTTP/1.0 401 Authorization Required" Header so the browser ask me to insert a login. But I can't handle with the Header the browser sent back.

So far I have a string with the http headers (String HTTP_req, in my code) and the length of string (HTTP_reqLenght, in my code).

GET / HTTP/1.1
Host: 192.168.1.210
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Authorization: Basic YWRtaW46YWRtaW4=

I am trying to use substring to compare the login but I can't got anything:

if (HTTP_req.substring(HTTP_reqLenght-16) == "YWRtaW46YWRtaW4=")
          {
          
              Serial.println("Got an OK from the server");
          }

I try substring because the Authorization Header appears always at the end of all headers I think.

I try to understand this library and applied to this webserver example but it is to confuse :S

Can anyone give me a hint to do that?

The complete code:

#include <SPI.h>
#include <Ethernet.h>
#include "WebServer.h"

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 210);



String HTTP_req;            // stores the HTTP request
int HTTP_reqLenght=0;

boolean authorization=0;



// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  
  
  
  
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        String pass=""+c;
        
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        HTTP_req += c;  // save the HTTP request 1 char at a time
        
        
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          
          HTTP_reqLenght=HTTP_req.length();
          Serial.print("\nHTTP REQUEST STRING\n");
          Serial.println(HTTP_req);
         
          
          if (HTTP_req.substring(HTTP_reqLenght-16) == "YWRtaW46YWRtaW4=")
          {
         
              Serial.println("Got an OK from the server");
          }
          
          
          if(authorization){
            client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("
");
          }
          client.println("</html>");
          }else{
            Unauthorized(client);
          }   
          
          
          
          
          
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
    HTTP_req="";
  }
}


void Unauthorized(EthernetClient client)
{
  client.println("HTTP/1.0 401 Authorization Required");
  client.println("Content-Type: text/html");
  client.println("WWW-Authenticate: Basic realm=\"Private Area\"");
}

I'm not sure what you are doing, but this
YWRtaW46YWRtaW4=
does not equal this
dXNlcjp1c2Vy

Thanks for correction. I try with admin:admin in the example above and ask for user:user. I edited the first post.

But when I test I use the correct credentials and I want to know how I can compare the login written from user with the login the browser received.

I print the HTTP_req.substring(HTTP_reqLenght-16) to saw what is going on and I have:

"aW46YWRtaW4=" in it. Instead of "YWRtaW46YWRtaW4="

There is some invisible characters I need to consider?

Or there is a better way to compare this thing?

Edit:

If I consider HTTP_req.substring(HTTP_reqLenght-20) I have the right characters but the code don't pass through the if statement.

HTTP REQUEST STRING
GET / HTTP/1.1
Host: 192.168.1.210
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Authorization: Basic YWRtaW46YWRtaW4=


Login written
YWRtaW46YWRtaW4=
if (HTTP_req.substring(HTTP_reqLenght-20) == "YWRtaW46YWRtaW4=")
          {
              Serial.println("Got an OK from the server");
          }else{
              Serial.println("Login written");
              Serial.print(HTTP_req.substring(HTTP_reqLenght-20));

          }

I found the solution using this class

if (find_text("YWRtaW46YWRtaW4=",HTTP_req)>0) {
   Serial.println("LOGIN SUCESSFULLY");
   //page here
}else{
   Serial.println("LOGIN WRONG");
   //error page here
}

Thanks for your help SurferTim (again) :smiley:

I think is a good solution to simplify the code.

I found the solution using this class

If you are using Strings, you probably can just use String.indexOf() like below.

// zoomkat 8-6-10 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

//A very simple example of sending a string of characters 
//from the serial monitor, capturing the individual 
//characters into a String, then evaluating the contents 
//of the String to possibly perform an action (on/off board LED).

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial on/off test 0021"); // so I can keep track
}

void loop() {

  while (Serial.available()) {
    delay(3);  
    char c = Serial.read();
    readString += c; 
  }

  if (readString.length() >0) {
    Serial.println(readString);

    if(readString.indexOf("on") >=0)
    {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON");
    }

    if(readString.indexOf("off") >=0)
    {
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF");
    }

    readString="";
  } 
}

Thanks. It works and with that I don't need an extra class.

If I open the page in two browsers if I logon in the first one, the second don't ask for the login. Is it normal? Or it happens because the IP is the same?

Edited:

The webserver is not working well:

If I enter in another browser at same time and then close the pages in the two browsers and trying to open again I only see a blank page.

In my project I am trying to use this tutorial.

Any ideas what is wrong?

When the page is blank and I refresh the browser the program go at this point:
else { // web page request
}

It is correct. Should show the page but nothing happens.

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
                htmlHeaders += c;  // string com informação do cliente
                // limit the size of the stored received HTTP request
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    
                    #ifdef DEBUG
                      Serial.print(htmlHeaders);
                    #endif

                    //auth accepted
                    if (htmlHeaders.indexOf("bHc5Omx3OQ==")>0) {
                      // send a standard http response header
                      client.println(F("HTTP/1.1 200 OK"));
                      
                      // remainder of header follows below, depending on if
                      // web page or XML page is requested
                      // Ajax request - send XML file
                      if (StrContains(HTTP_req, "ajax_inputs")) {
                          // send rest of HTTP header
                          client.println(F("Content-Type: text/xml"));
                          client.println(F("Connection: keep-alive"));
                          client.println();
                          SetQ();
                          // send XML file containing input states
                          XML_response(client);
                      }
                      else {  // web page request
                          // send rest of HTTP header
                          client.println(F("Content-Type: text/html"));
                          client.println(F("Connection: keep-alive"));
                          client.println();
                          // send web page
                          webFile = SD.open("index.htm");        // open web page file
                          if (webFile) {
                              while(webFile.available()) {
                                  client.write(webFile.read()); // send web page to client
                              }
                              webFile.close();
                          }
                      }
                    }else{
                      //auth required
                      client.println(F("HTTP/1.0 401 Authorization Required"));
                      client.println(F("Content-Type: text/html"));
                      client.println(F("WWW-Authenticate: Basic realm=\"Private Area\""));
                    }

                   
                    // display received HTTP request on serial port
                    #ifdef DEBUG
                      Serial.print(HTTP_req);
                    #endif

                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
GET /ajax_inputs&nocache=55469.004929395436 HTTP/1.1
Host: 192.168.1.156:8081
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.156:8081/
Connection: keep-alive

GET /favicon.ico HTTP/1.1
Host: 192.168.1.156:8081
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36
Accept: */*
Referer: http://192.168.1.156:8081/
Accept-Encoding: gzip, de

In the serial monitor says "GET /favicon.ico" but I don't have anything mention a favicon in html code.

I am connecting the arduino direct to PC. I will try with a router and 2 PCs to know if that resolves the problem.

In the serial monitor says "GET /favicon.ico" but I don't have anything mention a favicon in html code.

favicon.ico is a second request made by the browser for an icon that might represent the page.

I have the Arduino broken, that is what makes the arduino not open the page after while.

I substitute it for a new one and works fine now.

I have the doubt of the login.

bl0w:
If I open the page in two browsers if I logon in the first one, the second don't ask for the login. Is it normal?

I try it in two different computers and in the second computer don't ask for password.

There's some trick I can use to correct this?