440 likes | 597 Views
A digression. The next feature of programming HTTP clients that we will consider is user authentication Before considering that, however, we will digress to consider a commonly-used user authentication technique. Basic HTTP Authentication. Before giving a document to a client,
E N D
A digression • The next feature of programming HTTP clients that we will consider is user authentication • Before considering that, however, we will digress to consider a commonly-used user authentication technique
Basic HTTP Authentication • Before giving a document to a client, • a HTTP server looks for access-control files in every directory of the path to the document • if it finds one, it only serves the document to the client if the client can prove entitlement • By default, the access-control files are called .htaccess • But, in Apache-style servers at least, a list of names for such files can be specified using the AccessFileName directive when configuring the server (See http://httpd.apache.org/docs/1.3/mod/core.html#accessfilename )
Basic HTTP Authentication (contd.) • To use Basic HTTP Authentication to control access to a directory and its sub-directories, • create, in the directory, a file with one of the names specified in the AccessFileName directive • normally, this means a file called .htaccess • At its simplest, the contents of the file will look like this: AuthName "Some string to name this restricted area" AuthType Basic AuthUserFile path/to/some/password/file require user valid-user • This specifies • that only a client which can identify itself according to the password file should be given access to this directory and its contents • a name for the restricted area of the disk -- this name will be given to the client trying to access any file in this part of the disk, to help remind it of the right name+password to use
Basic HTTP Authentication (contd.) • Suppose I want to protect all contents of the directory http://www.cs.ucc.ie/j.bowen/cs4408/resources/demosecure/ • I could place in that directory a .htaccess file containing: AuthName "This info is restricted to CS 4408 students" AuthType Basic AuthUserFile /www/docs/j.bowen/cs4408/resources/.htpasswd require user valid-user • Then I would use the htpasswd utility provided by Apache to insert names+passwords for all eligible people into a file called .htpasswd in the parent resources directory • Any person trying to use a browser to access this directory would receive this challenge window:
Basic HTTP Authentication (contd.) • If the user fails to provide acceptable authentication, he/she would receive the screen shown on the bottom right
Using MSIE to try to get a document from this directory • Suppose we put a copy of showRequest2.phpin this directory • Suppose we try to use Microsoft Internet Explorer to try to read the output from showRequest2.php • Suppose we fail to provide the correct password • We get the page shown below
A "home-made browser" which attempts to get the same output • Now suppose this "home-made" browser tries to read the same file http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser6.php <?php require_once "HTTP/Request.php"; $req = &new HTTP_Request("http://www.cs.ucc.ie/j.bowen/cs4408/resources/demosecure/showRequest2.php"); if (!PEAR::isError($req->sendRequest())) { echo "<br><strong style='color:red'>Headers</strong>"; $headers = $req->getResponseHeader(); foreach ($headers as $name => $value) { echo "<br> $name = $value"; } echo "<br><strong style='color:red'>Cookies</strong><br>"; $cookies = $req->getResponseCookies(); foreach ($cookies as $fields) { foreach ($fields as $name => $value) { echo "$name = $value; "; }echo "<br>"; } $contents= $req->getResponseBody(); echo "<br><strong style='color:red'>Body</strong><br>"; echo $contents; } ?>
Results of running this "browser" • The response contains a WWW-Authenticate header, which specifies that Basic authentication is in force for this disk area, a "realm" called "This info is restricted to CS 4408 students" • The message body contains the HTML page that we got when we tried to use Microsoft Internet Explorer
A "browser" which provides authentication for this realm • At http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser7.php <?php require_once "HTTP/Request.php"; $req = &new HTTP_Request("http://www.cs.ucc.ie/j.bowen/cs4408/resources/demosecure/showRequest2.php"); $req->setBasicAuth("peadar", "foo"); if (!PEAR::isError($req->sendRequest())) { echo "<br><strong style='color:red'>Headers</strong>"; $headers = $req->getResponseHeader(); foreach ($headers as $name => $value) { echo "<br> $name = $value"; } echo "<br><strong style='color:red'>Cookies</strong><br>"; $cookies = $req->getResponseCookies(); foreach ($cookies as $fields) { foreach ($fields as $name => $value) { echo "$name = $value; "; }echo "<br>"; } $contents= $req->getResponseBody(); echo "<br><strong style='color:red'>Body</strong><br>"; echo $contents; } ?>
Results of running this "browser" • Request is accepted -- user+password are in SERVER vars $PHP_AUTH_USER, $PHP_AUTH_PW which we saw, last year, when we did server-side user-authentication in a PHP program
Another Approach to authentication • Instead of depending on the server demon to defend directories, we can • make our own programs defend themselves on a program-by-program basis
PHP-based handling of passwords on both client-side and server-side • We have just seen how to program a client to send a user+password • Last year, we saw how to write a server-side PHP program which demanded that the client authenticate itself • Let's revise that and see how we can use PHP for both sides of the authentication process
Server-side User-authentication in PHP • A server-side program can use the header() function to send headers requiring authentication • This will cause a browser to pop up a username/password/realm dialog window and • When the values have been provided by the user, the browser will send a new request back to the same page containing the appropriate information • When ther, some special PHP variables will be set: $PHP_AUTH_USER or $_SERVER["PHP_AUTH_USER"] $PHP_AUTH_PW or $_SERVER["PHP_AUTH_PW"]
User-authentication in PHP (contd.) • Consider the following program which is here: http://www.cs.ucc.ie/j.bowen/cs4408/resources/securePage.php <?php if ( ($_SERVER["PHP_AUTH_USER"]=='pedro') && ($_SERVER["PHP_AUTH_PW"]=='qwerty') ) { echo "<h1>Welcome</h1>"; } else {header("HTTP/1.0 401 Unauthorized"); header("WWW-Authenticate: Basic realm=BankAccounts"); echo "<h1>You must identify yourself</h1>"; echo "<p>Please provide a correct user+password</p>"; } ?>
Accessing this program through a normal browser • When first called by the browser, no user name or password is provided • When the WWW-Authenticate header is received by the browser, it asks the user for a username+password • If he gets it right, he is welcomed • Otherwise, he is told to that he must identify himself as a user who is entitled to visit the page
A "browser" which provides wrong details for this realm • At http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser8.php <?php require_once "HTTP/Request.php"; $req = &new HTTP_Request("http://www.cs.ucc.ie/j.bowen/cs4408/resources/securePage.php"); $req->setBasicAuth("peader", "foo"); if (!PEAR::isError($req->sendRequest())) {echo "<br><strong style='color:red'>Headers</strong>"; $headers = $req->getResponseHeader(); foreach ($headers as $name => $value) { echo "<br> $name = $value"; } echo "<br><strong style='color:red'>Cookies</strong><br>"; $cookies = $req->getResponseCookies(); foreach ($cookies as $fields) { foreach ($fields as $name => $value) { echo "$name = $value; "; } echo "<br>"; } $contents= $req->getResponseBody(); echo "<br><strong style='color:red'>Body</strong><br>"; echo $contents; } ?>
Results of running this "browser" • Request is rejected because of wrong username and password
A "browser" which provides correct details for this realm • At http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser9.php <?php require_once "HTTP/Request.php"; $req = &new HTTP_Request("http://www.cs.ucc.ie/j.bowen/cs4408/resources/securePage.php"); $req->setBasicAuth("pedro", "qwerty"); if (!PEAR::isError($req->sendRequest())) {echo "<br><strong style='color:red'>Headers</strong>"; $headers = $req->getResponseHeader(); foreach ($headers as $name => $value) { echo "<br> $name = $value"; } echo "<br><strong style='color:red'>Cookies</strong><br>"; $cookies = $req->getResponseCookies(); foreach ($cookies as $fields) { foreach ($fields as $name => $value) { echo "$name = $value; "; } echo "<br>"; } $contents= $req->getResponseBody(); echo "<br><strong style='color:red'>Body</strong><br>"; echo $contents; } ?>
Results of running this "browser" • Request is accepted
User-authentication in PHP (contd.) • Remember that you cannot mix self-provision of user authentication with external user authentication • The PHP_AUTH variables will not be set if external authentication is also enabled for a directory which contains a PHP program that is trying to do self-provision of user authentication • This is to avoid trhe possibility that a script might reveals the password for a page that was protected through a traditional external mechanism, such as the .htaccess mechanism
Using proxies • HTTP supports both direct and indirect connections between servers and clients • Indirect connections transmit the request/response messages through one or more proxies
Using proxies (contd.) • This program, at http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser201.php uses a direct connection to the RTE server: <?php require_once "HTTP/Request.php"; $req = & new HTTP_Request('http://www.rte.ie/'); if (!PEAR::isError($req->sendRequest())) { $contents= $req->getResponseBody(); echo $contents;} ?>
Using proxies (contd.) • This program, at http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser202.php asks a proxy server to pass its request to the RTE server: <?php require_once "HTTP/Request.php"; $req = & new HTTP_Request('http://www.rte.ie/'); $req->setProxy("csproxy.ucc.ie", 80); if (!PEAR::isError($req->sendRequest())) { $contents= $req->getResponseBody(); echo $contents;} ?>
Uploading files • Last year, we saw how to write PHP programs which would accept files being uploaded from a browser • We will review that material before going on to see how we can write our own clients to upload files to servers
File upload form <html> <head> <title>Upload a File</title> </head> <body> <h1>Upload a File</h1> <form enctype="multipart/form-data" method="post" action="uploadFile.php"> <p>File to Upload: <input type="file" name=“file1" size="30"></p> <p><button input type="submit“> "Upload File“</button></p> </form> </body> </html>
File upload script <html> <head> <title>File Upload Report</title> </head> <body> <h1>File Upload Report</h1> <p> <?php if ($file1_name != ‘’) { copy("$file1 ", "/full/path/to/your/target/directory/$file1_name") or die(“Couldnot copy the file! Are directory permissions correct? </p></body></html>"); echo “The following file has been received: “; echo “$file1_namecontaining$file1_size bytes and of MIME type $file1_type"; } else { die(“You did not specify an input file </p></body></html> ");}?> </p> </body> </html>
Newer convention • Newer versions of PHP store all the uploaded file information in the $_FILES autoglobal array. • $_FILES['userfile']['name'] • The original name of the file on the client machine. • $_FILES['userfile']['type'] • The mime type of the file, if the browser provided this information. An example would be `"image/gif"`. • $_FILES['userfile']['size'] • The size, in bytes, of the uploaded file. • $_FILES['userfile']['tmp_name'] • The temporary filename of the file in which the uploaded file was stored on the server.
Part 1 of newer version of program • Program available at: http://www.cs.ucc.ie/j.bowen/cs4408/resources/fileUploader.php • It will only work if it has write permission for directory/www/docs/j.bowen/cs4408/resources/upload/ <html> <head><title>File uploader</title></head> <body> <?php if (!$_POST["uploadingFile"]) { ?><h1>Upload a File</h1> <form enctype="multipart/form-data" method="post" action="fileUploader.php"> <p>File to Upload: <input type="file" name="file1" size="30"></p> <input type="hidden" name="uploadingFile" value="1"> <p><button input type="submit">Upload File</button></p> </form> <?php }
Part 2 of newer version of program else {?> <h1>File Upload Report</h1><p> <?php $file1_name=$_FILES["file1"]["name"]; $file1_type=$_FILES["file1"]["type"]; $file1_size=$_FILES["file1"]["size"]; $file1=$_FILES["file1"]["tmp_name"]; if ( $file1_name != "" ) { $uploadDirectory = '/www/docs/j.bowen/cs4408/resources/upload/'; $destinationFile= $uploadDirectory.$file1_name; move_uploaded_file($file1, $destinationFile) or die("Could not copy the file! Are directory permissions correct?"); ?>The following file has been received: <?php echo $file1_name; ?> containing <?php echo $file1_size; ?> bytes and of MIME type <?php echo $file1_type; ?><?php } else { die("You did not specify an input file </p>"); } ?> <?php } ?> </p></body></html>
A client which uploads a file to the same program • Suppose we want to write our own client which will upload a file to this program: http://www.cs.ucc.ie/j.bowen/cs4408/resources/fileUploader.php • Remember that the program fileUploader.php expects to receive data from a form on which there are the following input boxes: <input type="file" name="file1" size="30"> <input type="hidden" name="uploadingFile" value="1"> • Our client must send a request which contains data that looks as if it comes from these two inputs • That it, it must send, as POST data, the equation uploadingFile=1 • and it must send a file as it it were sent from a file input called file1
A client which uploads a file to the same program • This client is available here http://cosmos.ucc.ie/~jabowen/cs4408/myBrowser10.php • It uploads a file called courses.txt from a sub-directory, called demoDir, of the directory which contains the client program itself <?php require_once "HTTP/Request.php"; $req =& new HTTP_Request("http://www.cs.ucc.ie/j.bowen/cs4408/resources/fileUploader.php"); $req->setMethod(HTTP_REQUEST_METHOD_POST); $req->addPostData("uploadingFile", "1"); $result = $req->addFile("file1", "demoDir/courses.txt"); if (!PEAR::isError($result)) { $response = $req->sendRequest(); if (!PEAR::isError($response)) { echo $req->getResponseBody(); } } ?>