bug 19646 Localization of img_auth.php - with enhancements
authorJack D. Pond <jdpond@users.mediawiki.org>
Fri, 4 Sep 2009 02:44:05 +0000 (02:44 +0000)
committerJack D. Pond <jdpond@users.mediawiki.org>
Fri, 4 Sep 2009 02:44:05 +0000 (02:44 +0000)
https://bugzilla.wikimedia.org/show_bug.cgi?id=19646

1. Localize img_auth.php using core messages
2. Reorder checks to make sense (and eliminate redundancy)n
3. Add hook 'ImgAuthBeforeStream' to allow custom checking
4. Add globals wgImgAuthDetails,
5. Move all "wfDebugLog" into the rejection functions

img_auth.php
includes/DefaultSettings.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc

index cd8ec43..4764b78 100644 (file)
 /**
  * Image authorisation script
  *
- * To use this:
+ * To use this, see http://www.mediawiki.org/wiki/Manual:Image_Authorization
  *
  * - Set $wgUploadDirectory to a non-public directory (not web accessible)
  * - Set $wgUploadPath to point to this file
  *
- * Your server needs to support PATH_INFO; CGI-based configurations
- * usually don't.
+ * Optional Parameters
+ *
+ * - Set $wgImgAuthDetails = true if you want the reason the access was denied messages to be displayed 
+ *       instead of just the 403 error (doesn't work on IE anyway),  otherwise will only appear in error logs
+ * - Set $wgImgAuthPublicTest false if you don't want to just check and see if all are public
+ *       must be set to false if using specific restrictions such as LockDown or NSFileRepo
+ *
+ *  For security reasons, you usually don't want your user to know *why* access was denied, just that it was.
+ *  If you want to change this, you can set $wgImgAuthDetails to 'true' in localsettings.php and it will give the user the reason
+ *  why access was denied.
+ *
+ * Your server needs to support PATH_INFO; CGI-based configurations usually don't.
  *
  * @file
- */
+ *
+ **/
+
 define( 'MW_NO_OUTPUT_COMPRESSION', 1 );
 require_once( dirname( __FILE__ ) . '/includes/WebStart.php' );
 wfProfileIn( 'img_auth.php' );
 require_once( dirname( __FILE__ ) . '/includes/StreamFile.php' );
 
 $perms = User::getGroupPermissions( array( '*' ) );
-if ( in_array( 'read', $perms, true ) ) {
-       wfDebugLog( 'img_auth', 'Public wiki' );
-       wfPublicError();
-}
+
+// See if this is a public Wiki (no protections)
+if ( $wgImgAuthPublicTest && in_array( 'read', $perms, true ) )
+       wfForbidden('img-auth-accessdenied','img-auth-public');
 
 // Extract path and image information
-if( !isset( $_SERVER['PATH_INFO'] ) ) {
-       wfDebugLog( 'img_auth', 'Missing PATH_INFO' );
-       wfForbidden();
-}
+if( !isset( $_SERVER['PATH_INFO'] ) )
+       wfForbidden('img-auth-accessdenied','img-auth-nopathinfo');
 
 $path = $_SERVER['PATH_INFO'];
 $filename = realpath( $wgUploadDirectory . $_SERVER['PATH_INFO'] );
 $realUpload = realpath( $wgUploadDirectory );
-wfDebugLog( 'img_auth', "\$path is {$path}" );
-wfDebugLog( 'img_auth', "\$filename is {$filename}" );
 
 // Basic directory traversal check
-if( substr( $filename, 0, strlen( $realUpload ) ) != $realUpload ) {
-       wfDebugLog( 'img_auth', 'Requested path not in upload directory' );
-       wfForbidden();
-}
+if( substr( $filename, 0, strlen( $realUpload ) ) != $realUpload )
+       wfForbidden('img-auth-accessdenied','img-auth-notindir');
 
 // Extract the file name and chop off the size specifier
 // (e.g. 120px-Foo.png => Foo.png)
 $name = wfBaseName( $path );
 if( preg_match( '!\d+px-(.*)!i', $name, $m ) )
        $name = $m[1];
-wfDebugLog( 'img_auth', "\$name is {$name}" );
+
+// Check to see if the file exists
+if( !file_exists( $filename ) )
+       wfForbidden('img-auth-accessdenied','img-auth-nofile',htmlspecialchars($filename));
+
+// Check to see if tried to access a directory
+if( is_dir( $filename ) )
+       wfForbidden('img-auth-accessdenied','img-auth-isdir',htmlspecialchars($filename));
+
 
 $title = Title::makeTitleSafe( NS_FILE, $name );
-if( !$title instanceof Title ) {
-       wfDebugLog( 'img_auth', "Unable to construct a valid Title from `{$name}`" );
-       wfForbidden();
-}
-if( !$title->userCanRead() ) {
-       wfDebugLog( 'img_auth', "User does not have access to read `{$name}`" );
-       wfForbidden();
-}
-$title = $title->getPrefixedText();
 
-// Check the whitelist if needed
-if( !$wgUser->getId() && ( !is_array( $wgWhitelistRead ) || !in_array( $title, $wgWhitelistRead ) ) ) {
-       wfDebugLog( 'img_auth', "Not logged in and `{$title}` not in whitelist." );
-       wfForbidden();
-}
+// See if could create the title object
+if( !$title instanceof Title ) 
+       wfForbidden('img-auth-accessdenied','img-auth-badtitle',htmlspecialchars($name));
+
+// Run hook
+if (!wfRunHooks( 'ImgAuthBeforeStream', array( &$title, &$path, &$name, &$result ) ) )
+       call_user_func_array('wfForbidden',merge_array(array($result[0],$result[1]),array_slice($result,2)));
+       
+//  Check user authorization for this title
+//  UserCanRead Checks Whitelist too
+if( !$title->userCanRead() )
+       wfForbidden('img-auth-accessdenied','img-auth-noread',htmlspecialchars($name));
 
-if( !file_exists( $filename ) ) {
-       wfDebugLog( 'img_auth', "`{$filename}` does not exist" );
-       wfForbidden();
-}
-if( is_dir( $filename ) ) {
-       wfDebugLog( 'img_auth', "`{$filename}` is a directory" );
-       wfForbidden();
-}
 
 // Stream the requested file
-wfDebugLog( 'img_auth', "Streaming `{$filename}`" );
+wfDebugLog( 'img_auth', "Streaming `".htmlspecialchars($filename)."`." );
 wfStreamFile( $filename, array( 'Cache-Control: private', 'Vary: Cookie' ) );
 wfLogProfilingData();
 
 /**
- * Issue a standard HTTP 403 Forbidden header and a basic
- * error message, then end the script
+ * Issue a standard HTTP 403 Forbidden header ($msg1-a message index, not a message) and an
+ * error message ($msg2, also a message index), (both required) then end the script
+ * subsequent arguments to $msg2 will be passed as parameters only for replacing in $msg2 
  */
-function wfForbidden() {
+function wfForbidden($msg1,$msg2) {
+       global $wgImgAuthDetails;
+       $args = func_get_args();
+       array_shift( $args );
+       array_shift( $args );
+       $MsgHdr = wfMsgHTML($msg1);
+       $detailMsg = call_user_func_array('wfMsgHTML',array_merge(array($wgImgAuthDetails ? $msg2 : 'badaccess-group0'),$args));
+       wfDebugLog('img_auth', "wfForbidden Hdr:".wfMsgExt( $msg1, array('language' => 'en'))." Msg: ".
+                               call_user_func_array('wfMsgExt',array_merge( array($msg2, array('language' => 'en')),$args)));
        header( 'HTTP/1.0 403 Forbidden' );
-       header( 'Vary: Cookie' );
+       header( 'Cache-Control: no-cache' );
        header( 'Content-Type: text/html; charset=utf-8' );
        echo <<<ENDS
 <html>
 <body>
-<h1>Access Denied</h1>
-<p>You need to log in to access files on this server.</p>
+<h1>$MsgHdr</h1>
+<p>$detailMsg</p>
 </body>
 </html>
 ENDS;
        wfLogProfilingData();
        exit();
 }
-
-/**
- * Show a 403 error for use when the wiki is public
- */
-function wfPublicError() {
-       header( 'HTTP/1.0 403 Forbidden' );
-       header( 'Content-Type: text/html; charset=utf-8' );
-       echo <<<ENDS
-<html>
-<body>
-<h1>Access Denied</h1>
-<p>The function of img_auth.php is to output files from a private wiki. This wiki
-is configured as a public wiki. For optimal security, img_auth.php is disabled in 
-this case.
-</p>
-</body>
-</html>
-ENDS;
-       wfLogProfilingData();
-       exit;
-}
-
index 985a6e4..a696564 100644 (file)
@@ -191,6 +191,14 @@ $wgFileStore['deleted']['directory'] = false;///< Defaults to $wgUploadDirectory
 $wgFileStore['deleted']['url'] = null;       ///< Private
 $wgFileStore['deleted']['hash'] = 3;         ///< 3-level subdirectory split
 
+
+/**
+ *  used only for img_auth script - see [[Image Authorization]]
+ */
+$wgImgAuthDetails   = false; ///< defaults to false - only set to true if you use img_auth and want the user to see details on why access failed
+$wgImgAuthPublicTest = true; ///< defaults to true - if public read is turned on, no need for img_auth, config error unless other access is used
+
+
 /**@{
  * File repository structures
  *
@@ -281,7 +289,6 @@ $wgForeignFileRepos = array();
  */
 $wgLegalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+";
 
-
 /**
  * The external URL protocols
  */
index 8871458..e489ae7 100644 (file)
@@ -2144,6 +2144,19 @@ If the problem persists, contact an [[Special:ListUsers/sysop|administrator]].',
 'upload-unknown-size'       => 'Unknown size',
 'upload-http-error'         => 'An HTTP error occured: $1',
 
+#img_auth script messages
+'img-auth-accessdenied'   => "Access Denied",
+'img-auth-desc'                  => 'Image authorisation script',
+'img-auth-nopathinfo'     => "Missing PATH_INFO.  Your server is not set up to pass this information - may be CGI-based and can't support img_auth. See http://www.mediawiki.org/wiki/Manual:Image_Authorization.",
+'img-auth-notindir'      => "Requested path is not in the configured upload directory.",
+'img-auth-badtitle'      => "Unable to construct a valid title from `$1`.",
+'img-auth-nologinnWL'     => "You are not logged in and `$1` not in whitelist.",
+'img-auth-nofile'            => "File `$1` does not exist.",
+'img-auth-isdir'                 => "you are trying to access a directory`$1`.  Only file access is allowed.",
+'img-auth-streaming'     => "Streaming `$1`.",
+'img-auth-public'                => "The function of img_auth.php is to output files from a private wiki. This wiki is configured as a public wiki. For optimal security, img_auth.php is disabled for this case.",
+'img-auth-noread'                => "User does not have access to read `$1`.",
+
 # Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
 'upload-curl-error6'       => 'Could not reach URL',
 'upload-curl-error6-text'  => 'The URL provided could not be reached.
index 3c56d55..52b86f0 100644 (file)
@@ -2641,6 +2641,19 @@ The message appears after the name of the patroller.',
 * $1 is a date (example: ''19 March 2008'')
 * $2 is a time (example: ''12:15'')",
 
+#img_auth script messages
+'img-auth-desc'                  => '[[Manual:Image Authorization]] script, see http://www.mediawiki.org/wiki/Manual:Image_Authorization',
+'img-auth-accessdenied'   => "[[Manual:Image Authorization]] Access Denied",
+'img-auth-nopathinfo'     => "[[Manual:Image Authorization]] Missing PATH_INFO - see english description",
+'img-auth-notindir'      => "[[Manual:Image Authorization]] when the specified path is not in upload directory.",
+'img-auth-badtitle'      => "[[Manual:Image Authorization]] bad title, $1 is the invalid title",
+'img-auth-nologinnWL'     => "[[Manual:Image Authorization]] logged in and file not whitelisted. $1 is the file not in whitelist.",
+'img-auth-nofile'            => "[[Manual:Image Authorization]] non existent file, $1 is the file that does not exist.",
+'img-auth-isdir'                 => "[[Manual:Image Authorization]] trying to access a directory instead of a file, $1 is the directory.",
+'img-auth-streaming'     => "[[Manual:Image Authorization]] is now streaming file specified by $1.",
+'img-auth-public'                => "[[Manual:Image Authorization]] an error message when the admin has configured the wiki to be a public wiki, but is using img_auth script - normally this is a configuration error, except when special restriction extensions are used",
+'img-auth-noread'                => "[[Manual:Image Authorization]] User does not have access to read file, $1 is the file",
+
 # Video information, used by Language::formatTimePeriod() to format lengths in the above messages
 'seconds-abbrev' => '{{optional}}',
 'minutes-abbrev' => '{{optional}}',
index 234be98..756eec4 100644 (file)
@@ -327,6 +327,17 @@ $wgMessageStructure = array(
                'anonnotice',
                'newsectionheaderdefaultlevel',
                'red-link-title',
+               'img-auth-accessdenied',
+               'img-auth-desc',
+               'img-auth-nopathinfo',
+               'img-auth-notindir',
+               'img-auth-badtitle',
+               'img-auth-nologinnWL',
+               'img-auth-nofile',
+               'img-auth-isdir',
+               'img-auth-streaming',
+               'img-auth-public',
+               'img-auth-noread',
        ),
        'nstab' => array(
                'nstab-main',