From c57a4c19abfa91dd0753d4ee99cea5f2fbd2795a Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 17 Feb 2016 17:56:03 +0100 Subject: [PATCH] add HTTP Basic Authorization to WS Client and Server see: #55 --- examples/WebSocketClient/WebSocketClient.ino | 1 + src/WebSockets.h | 2 + src/WebSocketsClient.cpp | 30 +++++++++++++ src/WebSocketsClient.h | 3 ++ src/WebSocketsServer.cpp | 45 ++++++++++++++++++++ src/WebSocketsServer.h | 27 +++++++++++- 6 files changed, 106 insertions(+), 2 deletions(-) diff --git a/examples/WebSocketClient/WebSocketClient.ino b/examples/WebSocketClient/WebSocketClient.ino index e68e97c..82a2cc8 100644 --- a/examples/WebSocketClient/WebSocketClient.ino +++ b/examples/WebSocketClient/WebSocketClient.ino @@ -77,6 +77,7 @@ void setup() { } webSocket.begin("192.168.0.123", 81); + //webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization webSocket.onEvent(webSocketEvent); } diff --git a/src/WebSockets.h b/src/WebSockets.h index 1d46ef1..df1211e 100644 --- a/src/WebSockets.h +++ b/src/WebSockets.h @@ -180,6 +180,8 @@ typedef struct { uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer WSMessageHeader_t cWsHeaderDecode; + String base64Authorization; ///< Base64 encoded Auth request + #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) String cHttpLine; ///< HTTP header lines #endif diff --git a/src/WebSocketsClient.cpp b/src/WebSocketsClient.cpp index 6c38d2a..0999f49 100644 --- a/src/WebSocketsClient.cpp +++ b/src/WebSocketsClient.cpp @@ -25,6 +25,7 @@ #include "WebSockets.h" #include "WebSocketsClient.h" + WebSocketsClient::WebSocketsClient() { _cbEvent = NULL; _client.num = 0; @@ -60,6 +61,7 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url, _client.cProtocol = protocol; _client.cExtensions = ""; _client.cVersion = 0; + _client.base64Authorization = ""; #ifdef ESP8266 randomSeed(RANDOM_REG32); @@ -202,6 +204,30 @@ void WebSocketsClient::disconnect(void) { } } +/** + * set the Authorizatio for the http request + * @param user const char * + * @param password const char * + */ +void WebSocketsClient::setAuthorization(const char * user, const char * password) { + if(user && password) { + String auth = user; + auth += ":"; + auth += password; + _client.base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length()); + } +} + +/** + * set the Authorizatio for the http request + * @param auth const char * base64 + */ +void WebSocketsClient::setAuthorization(const char * auth) { + if(auth) { + _client.base64Authorization = auth; + } +} + //################################################################################# //################################################################################# //################################################################################# @@ -374,6 +400,10 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n"; } + if(client->base64Authorization.length() > 0) { + handshake += "Authorization: Basic " + client->base64Authorization + "\r\n"; + } + handshake += "\r\n"; client->tcp->write(handshake.c_str(), handshake.length()); diff --git a/src/WebSocketsClient.h b/src/WebSocketsClient.h index 9a66e47..a263666 100644 --- a/src/WebSocketsClient.h +++ b/src/WebSocketsClient.h @@ -68,6 +68,9 @@ class WebSocketsClient: private WebSockets { void disconnect(void); + void setAuthorization(const char * user, const char * password); + void setAuthorization(const char * auth); + protected: String _host; uint16_t _port; diff --git a/src/WebSocketsServer.cpp b/src/WebSocketsServer.cpp index a81af57..e1448b3 100644 --- a/src/WebSocketsServer.cpp +++ b/src/WebSocketsServer.cpp @@ -80,6 +80,8 @@ void WebSocketsServer::begin(void) { client->cIsUpgrade = false; client->cIsWebsocket = false; + client->base64Authorization = ""; + client->cWsRXsize = 0; #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) client->cHttpLine = ""; @@ -262,6 +264,32 @@ void WebSocketsServer::disconnect(uint8_t num) { } } + + +/** + * set the Authorizatio for the http request + * @param user const char * + * @param password const char * + */ +void WebSocketsServer::setAuthorization(const char * user, const char * password) { + if(user && password) { + String auth = user; + auth += ":"; + auth += password; + _base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length()); + } +} + +/** + * set the Authorizatio for the http request + * @param auth const char * base64 + */ +void WebSocketsServer::setAuthorization(const char * auth) { + if(auth) { + _base64Authorization = auth; + } +} + #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) /** * get an IP for a client @@ -564,6 +592,8 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { client->cProtocol = headerValue; } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) { client->cExtensions = headerValue; + } else if(headerName.equalsIgnoreCase("Authorization")) { + client->base64Authorization = headerValue; } } else { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); @@ -583,6 +613,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion); + DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization); bool ok = (client->cIsUpgrade && client->cIsWebsocket); @@ -598,6 +629,20 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { } } + if(_base64Authorization.length() > 0) { + if(client->base64Authorization.length() > 0) { + String auth = "Basic "; + auth += _base64Authorization; + if(auth != client->base64Authorization) { + DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num); + handleAuthorizationFailed(client); + return; + } + } else { + ok = false; + } + } + if(ok) { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num); diff --git a/src/WebSocketsServer.h b/src/WebSocketsServer.h index bf51bfd..27d7f8b 100644 --- a/src/WebSocketsServer.h +++ b/src/WebSocketsServer.h @@ -78,6 +78,9 @@ public: void disconnect(void); void disconnect(uint8_t num); + void setAuthorization(const char * user, const char * password); + void setAuthorization(const char * auth); + #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) IPAddress remoteIP(uint8_t num); #endif @@ -86,6 +89,7 @@ protected: uint16_t _port; String _origin; String _protocol; + String _base64Authorization; ///< Base64 encoded Auth request WEBSOCKETS_NETWORK_SERVER_CLASS * _server; @@ -109,8 +113,8 @@ protected: /** - * called if a non Websocket connection is comming in. - * Note: can be overrided + * called if a non Websocket connection is coming in. + * Note: can be override * @param client WSclient_t * ptr to the client struct */ virtual void handleNonWebsocketConnection(WSclient_t * client) { @@ -126,6 +130,25 @@ protected: clientDisconnect(client); } + /** + * called if a non Authorization connection is coming in. + * Note: can be override + * @param client WSclient_t * ptr to the client struct + */ + virtual void handleAuthorizationFailed(WSclient_t *client) { + + client->tcp->write("HTTP/1.1 401 Unauthorized\r\n" + "Server: arduino-WebSocket-Server\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 45\r\n" + "Connection: close\r\n" + "Sec-WebSocket-Version: 13\r\n" + "WWW-Authenticate: Basic realm=\"WebSocket Server\"" + "\r\n" + "This Websocket server requires Authorization!"); + clientDisconnect(client); + } + /** * called for sending a Event to the app * @param num uint8_t