Browse Source

- read/write modern apache/nginx md5 .htpasswd files (only, replaces old crypt functions)
- update key for email password reset on every password change
- include ALL resources (nothing loaded from external servers)
- renamed some functions/buttons to make it more user friendly
- added nginx example configuration for directory permissions as nginx does not support .htaccess files
- does not use external binaries as apache htpasswd (my 1st md5 compatible version did)
- tested with PHP 7.4 running on docker

FloKra 3 years ago
parent
commit
8765d16617

+ 91 - 0
nginx/nginx_example.conf

@@ -0,0 +1,91 @@
+server {
+    listen 80;
+    listen [::]:80;
+    server_name example.mydomain.com;
+    return 301 https://example.mydomain.com$request_uri;
+}
+server {
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
+    server_name example.mydomain.com;
+    ssl_certificate /etc/letsencrypt/live/example.mydomain.com/fullchain.pem;
+    ssl_certificate_key /etc/letsencrypt/live/example.mydomain.com/privkey.pem;
+    
+	include /etc/nginx/tls-profile.conf;
+	ssl_prefer_server_ciphers   on;
+	
+	root    "/www/example";
+    index    index.html  index.htm  index.cgi  index.php  index.php5 ;
+    #error_page 400 401 402 403 404 405 406 407 408 500 501 502 503 504 505 @error_page;
+    error_page 400 402 403 404 405 406 407 408 500 501 502 503 504 505 @error_page;
+    error_page 401 /errorpages/401.htm;
+
+    location @error_page {
+        root /www/error_page;
+        rewrite ^ /$status.html break;
+    }
+    
+    gzip on;
+    gzip_disable "msie6";
+    gzip_vary on;
+    gzip_proxied expired no-cache no-store private auth;
+    #compression level
+    gzip_comp_level 6;
+    gzip_min_length 1000;
+    gzip_buffers 16 8k;
+    gzip_http_version 1.1;
+    # files to gzip
+    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
+	
+	location / {
+		auth_basic 				"Protected";
+		auth_basic_user_file 	/www/passwd/.htpasswd;
+		try_files $uri $uri/ =404;
+	}
+
+	location /errorpages {
+		auth_basic          off;
+		try_files $uri $uri/ =404;
+	}
+	location ~ \.css$ {
+		auth_basic          off;
+		try_files $uri $uri/ =404;
+	}
+	location ~ \.png$ {
+		auth_basic          off;
+		try_files $uri $uri/ =404;
+	}
+	location ~ \.ico$ {
+		auth_basic          off;
+		try_files $uri $uri/ =404;
+	}
+	
+	location /htadmin {
+		auth_basic          off;
+		try_files $uri $uri/ =404;
+	}
+	location /htadmin/config {
+		deny all;
+        return 404;
+	}
+	location /htadmin/includes {
+		deny all;
+        return 404;
+	}
+	location /htadmin/tools {
+		deny all;
+        return 404;
+	}
+	
+	location ~ \.php$ {
+        try_files $uri =404;
+        fastcgi_split_path_info ^(.+\.php)(/.+)$;
+        fastcgi_pass php:9000;
+        fastcgi_index index.php;
+        include fastcgi_params;
+        fastcgi_param HOST "example.mydomain.com";
+        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+        fastcgi_param PATH_INFO $fastcgi_path_info;
+    }
+	
+}

BIN
sites/html/htadmin/fonts/glyphicons-halflings-regular.ttf


BIN
sites/html/htadmin/fonts/glyphicons-halflings-regular.woff


BIN
sites/html/htadmin/fonts/glyphicons-halflings-regular.woff2


+ 1 - 1
sites/html/htadmin/includes/checklogin.php

@@ -5,7 +5,7 @@
 session_start();
 include_once("tools/util.php");
 if (!check_login()) {
-	header('LOCATION:login.php');
+	header('LOCATION:selfservice.php');
 	die();
 }
 ?>

+ 3 - 3
sites/html/htadmin/includes/head.php

@@ -7,14 +7,14 @@ if (!isset($ini)) {
 <html>
 <head>
 <!-- Latest compiled and minified CSS -->
-<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
+<link rel="stylesheet" href="/htadmin/styles/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
 
 <!-- Optional theme -->
-<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
+<link rel="stylesheet" href="/htadmin/styles/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
 
 <!-- Latest compiled and minified JavaScript -->
 <script src="script/jquery-1.12.0.min.js"></script>
-<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
+<script src="script/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
 <script src="script/script.js"></script>
 <link rel="stylesheet" href="styles/style.css">
 <meta name="viewport" content="width=device-width, initial-scale=1">

+ 8 - 10
sites/html/htadmin/includes/nav.php

@@ -5,15 +5,14 @@ if (check_login ()) {
 	<div class="container">
 		<div class="navbar-header">
 			<ul class="nav navbar-nav navbar-left">
-				<a class="navbar-brand" href="index.php"><span
-					class="glyphicon glyphicon-home">&nbsp;</span>
+				<a class="navbar-brand" href="/"><span
+					class="glyphicon glyphicon-home"></a>&nbsp;<a class="navbar-brand" href="index.php"></span>
 				<?php
 	echo $ini['app_title'];
-	?>
-				</a>
+	?></a>
+				<li><a href="selfservice.php">User Self Service</a></li>
 				<li><a href="adminpwd.php">Admin password</a></li>
 				<li><a href="logout.php">Logout</a></li>
-				<li><a href="selfservice.php">User Self Service</a></li>
 			</ul>
 		</div>
 	</div>
@@ -26,15 +25,14 @@ if (check_login ()) {
 		<div class="navbar-header">
 
 			<ul class="nav navbar-nav navbar-left">
-				<a class="navbar-brand" href="index.php"><span
-					class="glyphicon glyphicon-home">&nbsp;</span>
+				<a class="navbar-brand" href="/"><span
+					class="glyphicon glyphicon-home"></a>&nbsp;<a class="navbar-brand" href="selfservice.php"></span>
 				<?php
 	echo $ini['app_title'];
-	?>
-				</a>
-				<li><a href="login.php">Login</a></li>
+	?></a>
 				<li><a href="selfservice.php">User Self Service</a></li>
 				<li><a href="forgotten.php">Password forgotten</a></li>
+				<li><a href="login.php">Admin Login</a></li>
 			</ul>
 		</div>
 	</div>

+ 1 - 1
sites/html/htadmin/index.php

@@ -24,7 +24,7 @@ if (isset ( $_POST ['user'] )) {
 		$meta_model->user = $username;
 		$meta_model->email = $_POST ['email'];
 		$meta_model->name = $_POST ['name'];
-		$meta_model->mailkey = random_password(8);
+		$meta_model->mailkey = random_password(16);
 	}
 	
 	if (! check_username ( $username ) || ! check_password_quality ( $passwd )) {

+ 1 - 1
sites/html/htadmin/login.php

@@ -32,7 +32,7 @@ include_once ('includes/nav.php');
 <div class="container box">
 	<div class="row">
 		<div class="col-xs-12">
-			<h2>Please Login:</h2>
+			<h2>Admin Login:</h2>
 <?php
 
 

File diff suppressed because it is too large
+ 5 - 0
sites/html/htadmin/script/bootstrap.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/html/htadmin/styles/bootstrap-theme.min.css


File diff suppressed because it is too large
+ 4 - 0
sites/html/htadmin/styles/bootstrap.min.css


+ 61 - 5
sites/html/htadmin/tools/htpasswd.php

@@ -4,7 +4,7 @@ include_once ("hash_tool.php");
 /**
  * htpasswd tools for Apache Basic Auth.
  *
- * Uses crypt only!
+ * now uses crypt_apr1_md5
  */
 class htpasswd {
 	var $fp;
@@ -29,7 +29,7 @@ class htpasswd {
 			fwrite ( $bdfp, $htaccess_content );
 		}
 		
-		@$this->fp = @$this::open_or_create ( $htpasswdfile );
+		@$this->fp = @$this::open_or_create ( $htpasswdfile ) or die('Cannot open file for R/W: '.$htpasswdfile);
 		
 		if ($use_metadata) {
 			$htmetafile = $path . "/" . self::HTMETA_NAME;
@@ -94,7 +94,11 @@ class htpasswd {
 		if ($this->user_exists ( $username ))
 			return false;
 		fseek ( $this->fp, 0, SEEK_END );
-		fwrite ( $this->fp, $username . ':' . self::htcrypt ( $password ) . "\n" );
+		//fwrite ( $this->fp, $username . ':' . self::htcrypt ( $password ) . "\n" );
+		fwrite ( $this->fp, $username . ':' . self::crypt_apr1_md5 ( $password ) . "\n" );
+		// quick and dirty 1. solution to add crypt_apr1_md5 encrypted passwords using htpasswd program
+		// echo "htpasswd -bm \"$this->filename\" \"$username\" \"$password\"";
+		// exec("htpasswd -bm \"$this->filename\" \"$username\" \"$password\"");
 		return true;
 	}
 	function meta_add(meta_model $meta_model) {
@@ -139,11 +143,30 @@ class htpasswd {
 		rewind ( $this->fp );
 		while ( ! feof ( $this->fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $this->fp ) ) ) ) ) ) {
 			if ($lusername == $username) {
-				fseek ( $this->fp, (- 15 - strlen ( $username )), SEEK_CUR );
-				fwrite ( $this->fp, $username . ':' . self::htcrypt ( $password ) . "\n" );
+				//fseek ( $this->fp, (- 15 - strlen ( $username )), SEEK_CUR );
+				//fwrite ( $this->fp, $username . ':' . self::htcrypt ( $password ) . "\n" );
+				fseek ( $this->fp, (- 39 - strlen ( $username )), SEEK_CUR );
+				fwrite ( $this->fp, $username . ':' . self::crypt_apr1_md5 ( $password ) . "\n" );
 				return true;
 			}
 		}
+		rewind ( $this->fp );
+		while ( ! feof ( $this->fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $this->fp ) ) ) ) ) ) {
+			if ($lusername == $username) {
+				//exec("htpasswd -bm \"$this->filename\" \"$username\" \"$password\"");
+				if ($use_metadata) {
+					$meta_model = new meta_model ();
+					$meta_model->user = $username;
+					$meta_model->email = $_POST ['email'];
+					$meta_model->name = $_POST ['name'];
+					$meta_model->mailkey = random_password(16);
+				}
+				return true;
+			}
+		}
+		// quick and dirty 1. solution to add crypt_apr1_md5 encrypted passwords using htpasswd program
+		//echo "htpasswd -bm \"$this->filename\" \"$username\" \"$password\"";
+		//exec("htpasswd -bm \"$this->filename\" \"$username\" \"$password\"");
 		return false;
 	}
 	function meta_update(meta_model $meta_model) {
@@ -187,6 +210,39 @@ class htpasswd {
 	static function htcrypt($password) {
 		return crypt ( $password, substr ( str_replace ( '+', '.', base64_encode ( pack ( 'N4', mt_rand (), mt_rand (), mt_rand (), mt_rand () ) ) ), 0, 22 ) );
 	}
+	static function crypt_apr1_md5($plainpasswd)
+	{   
+		// htpassword function for Apache > 2.2.18, Nginx
+		// https://www.virendrachandak.com/techtalk/using-php-create-passwords-for-htpasswd-file/
+		// https://stackoverflow.com/questions/2994637/how-to-edit-htpasswd-using-php/8786956#8786956
+		$salt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 0, 8);
+		$len = strlen($plainpasswd);
+		$text = $plainpasswd.'$apr1$'.$salt;
+		$bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd));
+		for($i = $len; $i > 0; $i -= 16) { $text .= substr($bin, 0, min(16, $i)); }
+		for($i = $len; $i > 0; $i >>= 1) { $text .= ($i & 1) ? chr(0) : $plainpasswd{0}; }
+		$bin = pack("H32", md5($text));
+		for($i = 0; $i < 1000; $i++)
+		{
+			$new = ($i & 1) ? $plainpasswd : $bin;
+			if ($i % 3) $new .= $salt;
+			if ($i % 7) $new .= $plainpasswd;
+			$new .= ($i & 1) ? $bin : $plainpasswd;
+			$bin = pack("H32", md5($new));
+		}
+		for ($i = 0; $i < 5; $i++)
+		{
+			$k = $i + 6;
+			$j = $i + 12;
+			if ($j == 16) $j = 5;
+			$tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
+		}
+		$tmp = chr(0).chr(0).$bin[11].$tmp;
+		$tmp = strtr(strrev(substr(base64_encode($tmp), 2)),
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+		"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
+		return "$"."apr1"."$".$salt."$".$tmp;
+	}
 
 	
 	static function create_hash_tool($hash) {

Some files were not shown because too many files changed in this diff