소스 검색

Document mg_check_digest_access_authentication and add an example

bel2125 7 년 전
부모
커밋
efb1cdbb4c
4개의 변경된 파일103개의 추가작업 그리고 3개의 파일을 삭제
  1. 4 0
      docs/api/mg_check_digest_access_authentication.md
  2. 80 1
      examples/embedded_c/embedded_c.c
  3. 18 1
      include/civetweb.h
  4. 1 1
      src/main.c

+ 4 - 0
docs/api/mg_check_digest_access_authentication.md

@@ -23,6 +23,10 @@ information, matching user and password encoded within the password file.
 If the authentication realm (also called authentication domain) is NULL, the parameter
 `authentication_domain` as specified in the server configuration (`mg_start()`) is used.
 
+A positive return value means, the user name, realm and a correct password hash have been
+found in the passwords file.
+A return of 0 means, reading the password file succeeded, but there was no matching user,
+realm and password.
 The function returns a negative number on errors.
 
 ### See Also

+ 80 - 1
examples/embedded_c/embedded_c.c

@@ -86,9 +86,14 @@ ExampleHandler(struct mg_connection *conn, void *cbdata)
 
 #ifdef USE_WEBSOCKET
 	mg_printf(conn,
-	          "<p>To test websocket handler <a href=\"/websocket\">click "
+	          "<p>To test the websocket handler <a href=\"/websocket\">click "
 	          "websocket</a></p>");
 #endif
+
+	mg_printf(conn,
+	          "<p>To test the authentication handler <a href=\"/auth\">click "
+	          "auth</a></p>");
+
 	mg_printf(conn, "<p>To exit <a href=\"%s\">click exit</a></p>", EXIT_URI);
 	mg_printf(conn, "</body></html>\n");
 	return 1;
@@ -519,6 +524,76 @@ PostResponser(struct mg_connection *conn, void *cbdata)
 
 
 int
+AuthStartHandler(struct mg_connection *conn, void *cbdata)
+{
+	static unsigned long long firstload = 0;
+	const char *passfile = "password_example_file.txt";
+	const char *realm = "password_example";
+	const char *user = "user";
+	char passwd[64];
+
+	if (firstload == 0) {
+
+		/* Set a random password (4 digit number - bad idea from a security
+		 * point of view, but this is an API demo, not a security tutorial),
+		 * and store it in some directory within the document root (extremely
+		 * bad idea, but this is still not a security tutorial).
+		 * The reason we create a new password every time the server starts
+		 * is just for demonstration - we don't want the browser to store the
+		 * password, so when we repeat the test we start with a new password.
+		 */
+		firstload = (unsigned long long)time(NULL);
+		sprintf(passwd, "%04u", (unsigned int)(firstload % 10000));
+		mg_modify_passwords_file(passfile, realm, user, passwd);
+
+		/* Just tell the user the new password generated for this test. */
+		mg_printf(conn,
+		          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+		          "close\r\n\r\n");
+
+		mg_printf(conn, "<!DOCTYPE html>\n");
+		mg_printf(conn, "<html>\n<head>\n");
+		mg_printf(conn, "<meta charset=\"UTF-8\">\n");
+		mg_printf(conn, "<title>Auth handlerexample</title>\n");
+		mg_printf(conn, "</head>\n");
+
+		mg_printf(conn, "<body>\n");
+		mg_printf(conn,
+		          "<p>The first time you visit this page, it's free!</p>\n");
+		mg_printf(conn,
+		          "<p>Next time, use username \"%s\" and password \"%s\"</p>\n",
+		          user,
+		          passwd);
+		mg_printf(conn, "</body>\n</html>\n");
+
+		return 1;
+	}
+
+	if (mg_check_digest_access_authentication(conn, realm, passfile) > 0) {
+		/* No valid authorization */
+		mg_send_digest_access_authentication_request(conn, realm);
+		return 1;
+	}
+
+	mg_printf(conn,
+	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+	          "close\r\n\r\n");
+
+	mg_printf(conn, "<!DOCTYPE html>\n");
+	mg_printf(conn, "<html>\n<head>\n");
+	mg_printf(conn, "<meta charset=\"UTF-8\">\n");
+	mg_printf(conn, "<title>Auth handlerexample</title>\n");
+	mg_printf(conn, "</head>\n");
+
+	mg_printf(conn, "<body>\n");
+	mg_printf(conn, "<p>This is the password protected contents</p>\n");
+	mg_printf(conn, "</body>\n</html>\n");
+
+	return 1;
+}
+
+
+int
 WebSocketStartHandler(struct mg_connection *conn, void *cbdata)
 {
 	mg_printf(conn,
@@ -940,6 +1015,10 @@ main(int argc, char *argv[])
 	/* Add HTTP site to open a websocket connection */
 	mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
 
+	/* Add HTTP site with auth */
+	mg_set_request_handler(ctx, "/auth", AuthStartHandler, 0);
+
+
 #ifdef USE_WEBSOCKET
 	/* WS site for the websocket connection */
 	mg_set_websocket_handler(ctx,

+ 18 - 1
include/civetweb.h

@@ -788,7 +788,24 @@ mg_send_digest_access_authentication_request(struct mg_connection *conn,
                                              const char *realm);
 
 
-/* TODO: Test and document */
+/* Check if the current request has a valid authentication token set.
+ * A file is used to provide a list of valid user names, realms and
+ * password hashes. The file can be created and modified using the
+ * mg_modify_passwords_file API function.
+ * Parameters:
+ *   conn: Current connection handle.
+ *   realm: Authentication realm. If NULL is supplied, the sever domain
+ *          set in the authentication_domain configuration is used.
+ *   filename: Path and name of a file storing multiple password hashes.
+ * Return:
+ *   > 0   Valid authentication
+ *   0     Invalid authentication
+ *   < 0   Error (all values < 0 should be considered as invalid
+ *         authentication, future error codes will have negative
+ *         numbers)
+ *   -1    Parameter error
+ *   -2    File not found
+ */
 CIVETWEB_API int
 mg_check_digest_access_authentication(struct mg_connection *conn,
                                       const char *realm,

+ 1 - 1
src/main.c

@@ -192,7 +192,7 @@ static NO_RETURN void
 die(const char *fmt, ...)
 {
 	va_list ap;
-    char msg[512] = "";
+	char msg[512] = "";
 
 	va_start(ap, fmt);
 	(void)vsnprintf(msg, sizeof(msg) - 1, fmt, ap);