Subversion Repositories web_pages

Rev

Rev 14 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
12 rodolico 1
<?php
14 rodolico 2
/**
3
 * Copyright (c) 2025, Daily Data, Inc.
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without modification,
7
 * are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this list
10
 *    of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright notice, this
12
 *    list of conditions and the following disclaimer in the documentation and/or other
13
 *    materials provided with the distribution.
14
 * 3. Neither the name of Daily Data, Inc. nor the names of its contributors may be
15
 *    used to endorse or promote products derived from this software without specific
16
 *    prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
21
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27
 * DAMAGE.
28
 */
12 rodolico 29
 
30
/**
31
 
14 rodolico 32
   PHP script which reads configuration file containing user information. Users
33
   are presented with a username and password box and a router selector.
34
   When processed, will read data file and determine if the credentials match any line
35
   and
36
   * display a QR Code suitable for scanning with one time authentication app
37
   * display the OTP seed code in case user wants to enter it manually
38
   * provide a link to download the OpenVPN configuration file for that user
12 rodolico 39
 
14 rodolico 40
   Assumes configuration file generated by loadOpnSense.pl
41
   Assumes QR code images are pre-generated and stored in a web accessible location
42
   Assumes OpenVPN configuration files are pre-generated and stored in a web accessible location
43
   Assumes passwords are hashed using password_hash function
12 rodolico 44
 
14 rodolico 45
   The configuration file is a json file with the following structure
46
   {
47
      "router1" : {
48
         "users" : {
49
            "user1" : {
50
               "password" : "<hashed password>",
51
               "otp_seed" : "<otp seed>",
52
               "qrFile" : "<path to qr code image file>",
53
               "ovpnFile" : "<path to openvpn config file>"
54
            },
55
            "user2" : {
56
               ...
57
            }
58
         }
59
      },
60
      "router2" : {
61
         ...
62
      }
63
   }
12 rodolico 64
 
14 rodolico 65
   Version 1.0.0 RWR 2025-09-21
66
      Initial Release
67
   Version 1.1.0 RWR 2025-09-27
68
      Added capability of downloading VPN configuration file
69
   Version 1.2.0 RWR 2025-10-01
70
     Reading from json file instead of csv
71
     Removed dependency on exec and external commands
72
     Added logging of successful logins
73
     automatically generate router list from config file
74
     Added some error checking for missing qr code image file and ovpn file
12 rodolico 75
 
76
 */
77
 
14 rodolico 78
// this is the only variable you may need to change
79
// everything else is in the configuration file
80
$configFile = './users.json';
13 rodolico 81
 
14 rodolico 82
// we need the config data for form processing and validation, so always load it
83
if ( file_exists( $configFile ) ) {
84
   $configData = json_decode( file_get_contents( $configFile ), true );
85
} else {
86
   die( "Configuration file $configFile not found" );
87
}
13 rodolico 88
 
12 rodolico 89
// Check if the form is submitted
90
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
14 rodolico 91
   // Get the username and password from the form
12 rodolico 92
    $username = $_POST['username'];
93
    $password = $_POST['password'];
94
    $router = $_POST['router'];
95
 
14 rodolico 96
    if ( $configData ) {
15 rodolico 97
      $isValidUser = false;
14 rodolico 98
      if ( isset( $configData[$router]) && isset( $configData[$router]['users'][$username] ) ) {
99
         $data = $configData[$router]['users'][$username];
100
         if ( password_verify( $password, $data['password'] ) ) {
101
            $isValidUser = true;
15 rodolico 102
            $code = $data['otp_seed'];
14 rodolico 103
            $imageFileName = $data['qrFile'];
104
            $ovpnFileName = $data['ovpnFile'];
105
            $log = date("Y-m-d H:i:s") . "\t" . $_SERVER['REMOTE_ADDR'] . "\t" .
106
            "Success\t" . $username."\t" .PHP_EOL;
107
            file_put_contents( './log_'.date("j.n.Y").'.log', $log, FILE_APPEND );
12 rodolico 108
         }
109
      }
14 rodolico 110
   } else {
111
      print '<h1>Could not open the configuration file.</h1>';
112
   }
113
   if ( ! $isValidUser )
114
         print "<h1>Password wrong, or invalid user $username for router $router</h1>";
115
} // if form submitted
13 rodolico 116
 
12 rodolico 117
?>
118
 
119
<!DOCTYPE html>
120
<html lang="en">
121
<head>
122
    <meta charset="UTF-8">
123
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
124
    <title>Get QR Code</title>
125
</head>
126
<body>
127
    <?php
15 rodolico 128
       if ($_SERVER['REQUEST_METHOD'] == 'POST') {
129
          print "<div style='text-align: center;'>";
130
            if ( empty( $code ) || empty($imageFileName) || !file_exists($imageFileName)) {
131
               print "<p><b>QR Code image file not found</b></p>";
132
               print "<p>You may not be set up with a TOTP code on $router, talk to an administrator</p>";
133
            } else {
134
               // all good
135
               print "<img src='$imageFileName' alt='$code'>";
136
               print "<br />Your code for $router is<br /><b>$code</b>";
137
            }
138
            if ( empty( $ovpnFileName ) ) {
139
               print "<br />No OpenVPN configuration file available";
140
            } else {
141
               print "<br /><a href='$ovpnFileName' download>Download your OpenVPN Config File</a>";
142
            }
14 rodolico 143
         print '</div>';
144
      }
12 rodolico 145
    ?>
13 rodolico 146
    <p>This page is updated hourly. If change your password, it will not be reflected here for an hour</p>
12 rodolico 147
    <form method="POST" action="">
148
        <label for="username">Username:</label>
149
        <input type="text" id="username" name="username" required>
150
        <br>
151
        <label for="password">Password:</label>
152
        <input type="password" id="password" name="password" required>
153
        <br>
154
        <label for="router">Router:</label>
155
         <select name="router" id="router">
156
             <?php
14 rodolico 157
               // gets a list of all routers listed in $csvFile into array $routers
158
               $routers = array_keys( $configData );
12 rodolico 159
                #die( "<pre>" . print_r( $routers, true) . "</pre>" );
160
                foreach ( $routers as $index => $name ) {
161
                   print "<option value='$name'>$name</option>\n";
162
                }
163
            ?>
164
         </select>        
165
        <br>
166
        <input type="submit" value="Login">
167
    </form>
168
</body>
169
</html>