Please note: This is an unpublished site and we are making changes - glitches still!!!

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.