How to restrict admin usage
If we do not create an authentication mechanism anybody can go to our site and add pages with images from well-known Internet shock sites. We must definitely do something about it. Why not create a simple log-in system. Or maybe two?
Once again, this is something we must be able to extend later. So we can start from a very simple user authentication based on the configuration file and leave a slot for a more elaborate but simple one with a database table, user levels and user administration. I have so far written dozens of multi-user web applications and I know it can be made very simple.
The configuration file based authentication
Add the following lines to your settings.txt at admin/config
admin_login = admin
admin_pass = pass1234
This is a very stupid way of doing things but we have to start somewhere. Now let's create a login template and a login module. The template is there as we can use the UpdateForm without any problems. So the module is here:
<?php require_once "lib/Updateform.class.php"; class login_module extends CmsModule { function init(){ parent::init(); } function fetch(){ $form = new UpdateForm(); $form->setAction("./do_login"); // show nice subtitle $form->addSubTitle("Log in to the administration site"); $form->addField("_login","","Login username","text"); // use the "password" field type $form->addfield("_pass","","Password","password"); $form->setSubmitText("Log in"); // remove the cancel button by cleaning the text $form->setCancelText(""); $form->setSmarty(new Smarty()); return $form->fetchTemplate("UpdateForm.tpl"); } } ?>
This code will show the login screen. Save it to /admin/modules/login/login_module.php Now the only thing we need to do is create the autentication module. We will have two options in the module. The recommended one is to use the database and the non-recommended one is to use the config file. And this is how it goes:
<?php class dologin_module extends CmsModule{ // if $usedb==true we will use the database var $auth_type= "config"; var $table = "adminusers"; function init(){ parent::init(); // check the param "auth_type" if ($this->vars['auth_type']=='database') $this->auth_type= "database"; } // The fetch function combines two actions: "login" and "logout" function fetch(){ // are we logging out? if ($this->vars['action']=='logout'){ unset($_SESSION['logged_in']); unset($_SESSION['userlevel']); // done, direct the browser to front page header("Location: index.php?act=logged_out"); exit; } // logging in from this on // get the variables and tidy them $login = mysql_real_escape_string($_POST['_login']); $pass = mysql_real_escape_string($_POST['_pass']); $referer = $_SERVER['HTTP_REFERER']; if ($this->auth_type=="database"){ $query = "SELECT userlevel FROM $this->table " . "WHERE passwd='$pass' AND login='$login'"; $result = mysql_query($query); if (mysql_error()) die("DB Error"); if (mysql_num_rows($result)==0){ // login failure unset($_SESSION['logged_in']); } else { $row=mysql_fetch_row($result); $_SESSION['userlevel'] = $row[0]; $_SESSION['logged_in'] = 1; } } else { // Configuration file based log-in if (($login == $GLOBALS['cms_config']['admin_login']) && ($pass == $GLOBALS['cms_config']['admin_pass'])){ $_SESSION['userlevel'] = 9; // arbitrary high level $_SESSION['logged_in'] = 1; } else { unset($_SESSION['logged_in']); } } if ($_SESSION['logged_in']) header('Location: index.php'); else { $referer .= "&alert=Login failed"; header("Location: $referer"); } // finally exit to stop further processing exit; } } ?>
Okay, save this class to /admin/modules/login/dologin_module.php
Login changes in the main template
After we have done this the menus should work. However, if we want to play safe we must add some restrictive code to the logic. At its simplest it might be a simplest it may be one single conditional structure in the admin main template.
{if $smarty.get.act eq "login"}
{cmsmodule name="login" path="login" action="login"}
{elseif $smarty.post.act eq 'send_login'}
{cmsmodule name="dologin" path="login"}
{elseif $smarty.get.act eq 'logout'}
{cmsmodule name="dologin" path="login" action="logout"}
{elseif $smarty.get.act eq 'logged_out'}
{cmsmodule name="html" file="html/logged_out.html"}
{/if}
{if $smarty.session.logged_in eq "1"}
{* site news stuff *}
{if $smarty.get.act eq 'news_list'}
{cmsmodule name="news_list" path="news"}
{elseif $smarty.get.act eq 'edit_news'}
{cmsmodule name="news_edit" path="news"}
{elseif $smarty.post.act eq 'save_news'}
{cmsmodule name="news_save_article" path="news"}
{* lots of lines removed from here *}
{elseif $smarty.get.act eq "edit_config"}
{cmsmodule name="config_edit" path="modules/config"}
{elseif $smarty.post.act eq "save_config"}
{cmsmodule name="config_save" path="modules/config"}
{else}
{cmsmodule name="html" file="html/test.html"}
{/if}
{else}
{if $smarty.get.act ne "login"}
{cmsmodule name="html" file="html/must_log_in.html"}
{/if}
{/if}
Here the modules will never be loaded if the user has not logged in. There is nothing wrong with this approach if we only have one admin level. So let's leave it like this and fine-tune it later if we add user levels.
The validity of this site may vary while it is being
developed.
Feel free to test it, though :)