10.7.1 Controlled Access Applications - Continued

Here's the text of our security script, which can be used to provide multi-user password-protected access to an application. Since this code is useful in many applications, rather than copy it into each application script, we can make it a module and use it automatically in any application.

While we'll discuss modules in detail in the next section, for now just keep in mind that this script will be part of another application - in our case, the patent example script. With the following steps we can add this code to the patent script:

  1. Make this script a module with the command line:
    texis -ci -module security -log none file
    
    (assuming we saved the code to file ).

  2. Remove the patent script's <A nbsp;NAME=look> and <A nbsp;NAME=/look> functions. (Leave the calls to <look> etc. intact; we're replacing them with new versions here.)

  3. Add <USES nbsp;security> to the top of the patent script.
(Download this script.)


  <SCRIPT LANGUAGE=vortex>
  
  <!------------------------------------------------------------------>
  <A NAME=verifyuser EXPORT>
  <!-- Core function: checks the user's cookie and verifies their login;
    -- if not, redirects them to the login page.  Must be called before
    -- output.  Sets $User to user name, and $Perms to user's permissions.
    -->
    <$Perms = >
    <IF $User eq "">                          <!-- parse the cookie -->
      <$Pass = ><$vars = "User" "Pass">
      <decrypt $LoginCookie $SERVER_NAME>
      <readvars $vars $ret>                   <!-- get User, Pass -->
    </IF>
    <IF $User eq ""><redir></IF>              <!-- not logged in -->
    <SQL MAX=1 "select EncPass, Perms from passwd where User = $User">
    </SQL>
    <IF $loop eq 0><redir></IF>               <!-- no such user -->
    <pwencrypt $Pass $EncPass>
    <IF $ret neq $EncPass><redir></IF>        <!-- bad password -->
    <strfmt "User=%U&Pass=%U" $User $Pass>    <!-- raw cookie -->
    <encrypt $ret $SERVER_NAME>               <!-- encrypt it -->
    <header COOKIE="LoginCookie" VALUE=$ret>  <!-- make a  cookie -->
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=okperm EXPORT p bail=y>             <!-- check perm  -->
    <IF $Perms eq ""><$Perms = ""></IF>       <!-- let <strstr> work -->
    <strstr $p $Perms>
    <IF $ret eq -1 and $bail eq "y">
      <H2>Forbidden</H2>
      Sorry, you do not have $p privileges required for this page.
      </look><exit>
    </IF>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=look EXPORT chk=y title="">         <!-- header, check user -->
    <IF $chk eq "y"><verifyuser></IF>
    <IF $title neq ""> <HEAD><TITLE>$title</TITLE></HEAD> </IF>
    <BODY BGCOLOR=white>
    <IF $title neq ""> <H2>$title</H2><P> </IF>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=/look EXPORT>                       <!-- footer HTML, links -->
    <P><HR><A HREF=$url>Main Page</A>
     &nbsp;<A HREF=$url/login.html>Re-login</A>
    <okperm p="admin" bail=n>
    <IF $ret neq -1>                          <!-- extra links if admin -->
      &nbsp;&nbsp;&nbsp;<A HREF=$url/listusers.html>User List</A>
      &nbsp;<A HREF=$url/createuser.html>Create User</A>
      &nbsp;<A HREF=$url/deluser.html>Delete User</A>
    </IF>
    </BODY>
  </A>
  
  <A NAME=go PRIVATE say="">                  <!-- macro function -->
   <TR><TD ALIGN=right> </TD>
     <TD ALIGN=left> <INPUT TYPE=submit VALUE="$say"> </TD></TR>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=login PUBLIC>                       <!-- login page -->
    <look chk=n title="Login">
    <rex "/login\.html=>>=" $HTTP_REFERER>    <!-- where were they? -->
    <IF $ret neq "">                          <!-- they were just here -->
      Login incorrect.
    <ELSE>
      Please login with your user name and password:
    </IF>
    <P>
    <FORM METHOD=post ACTION=$url>
      <TABLE BORDER=0>
        <TR><TD ALIGN=right> User: </TD>
          <TD ALIGN=left> <INPUT NAME=User SIZE=16> </TD></TR>
        <TR><TD ALIGN=right> Password: </TD>
          <TD ALIGN=left> <INPUT TYPE=password NAME=Pass SIZE=16> </TD></TR>
        <go say="Login">
      </TABLE>
    </FORM>
    </look>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=redir PRIVATE>                      <!-- redirect to login -->
    <sum "%s" $urlroot "/login.html">
    <header NAME="Location" VALUE=$ret>
    Please <A HREF="$urlroot/login.html">login</A> first.
    <exit>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=createuser PUBLIC>                  <!-- create-user form -->
    <look title="Create New User">
    <okperm p="admin">                        <!-- are we admin? -->
    Enter the new user's data below: <P>
    <FORM METHOD=post ACTION=$url/docreate.html>
      <TABLE BORDER=0> <TR><TD ALIGN=right> User: </TD>
          <TD ALIGN=left> <INPUT NAME=newuser SIZE=16> </TD></TR>
        <TR><TD ALIGN=right> Password: </TD>
          <TD ALIGN=left> <INPUT TYPE=password NAME=newpass SIZE=16>
          </TD></TR>
        <TR><TD ALIGN=right> Permissions: </TD>
          <TD ALIGN=left> <$poss = "search" "insert" "admin">
            <checkbox newperms $poss "" $poss> </TD></TR>
        <go say="Create User">
      </TABLE>
    </FORM>
    </look>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=docreate PUBLIC>                    <!-- create user -->
    <look title="Create User">
    <okperm p="admin">                        <!-- are we admin? -->
    <IF $newuser eq ""> Please enter a user.     <exit> </IF>
    <IF $newpass eq ""> Please enter a password. <exit> </IF>
    <sum ",%s" "" $newperms>
    <substr $ret 2 -1>
    <$newperms = $ret>
    <IF $newperms eq "">
      You must select at least one permission.
      <exit>
    </IF>
    <pwencrypt $newpass ""><$epass = $ret>
    <SQL NOVARS
      "insert into passwd values(counter, $newuser, $epass, $newperms)">
    </SQL>
    <IF $loop eq 1> User $newuser created. </IF>
    </look>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=deluser PUBLIC>                     <!-- delete-user form -->
    <look title="Delete User">
    <okperm p="admin">                        <!-- are we admin? -->
    Delete a user: <P>
    <FORM METHOD=post ACTION=$url/dodel.html>
      <TABLE BORDER=0>  <TR><TD ALIGN=right> User: </TD>
          <TD ALIGN=left> <INPUT NAME=deluser SIZE=16 VALUE="$deluser">
          </TD></TR>
        <go say="Delete User">
      </TABLE>
    </FORM>
    </look>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=dodel PUBLIC>                       <!-- delete user -->
    <look title="Delete User">
    <okperm p="admin">                        <!-- are we admin? -->
    <IF $deluser eq ""> Please enter a user. <exit> </IF>
    <SQL NOVARS MAX=1 "delete from passwd where User = $deluser"></SQL>
    User $deluser deleted.
    </look>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=listusers PUBLIC>                   <!-- list all users -->
    <look title="User List">
    <okperm p="admin">                        <!-- are we admin? -->
    The existing users are: <P>
    <TABLE BORDER=0>
    <TR> <TH> </TH> <TH> User </TH><TH> Created </TH>
        <TH> Permissions </TH> </TR>
    <SQL ROW "select id, User u, Perms perms from passwd order by User">
      <TR> <strfmt "?deluser=%U" $u>
        <TD> <A HREF=$url/deluser.html$ret>Delete</A> </TD>
        <TD> $u </TD> <TD><fmt " %at " "%b %e %Y" $id></TD>
        <TD> $perms </TD> </TR>
    </SQL>
    </TABLE>
    </look>
  </A>
  
  <!------------------------------------------------------------------>
  <A NAME=mkadmin PUBLIC>                     <!-- bootstrap -->
    <IF $REMOTE_ADDR neq "">                  <!-- security check -->
      This function must be called from the command line.
      <exit>
    </IF>
    <SQL NOVARS "create table passwd(id counter, User varchar(10),
        EncPass varchar(10), Perms varchar(10))">
    </SQL>
    <SQL NOVARS "create unique index xpassu on passwd(User)"></SQL>
    admin users's password (ENTER then EOF char): <flush>
    <readln MAX=1 "-"></readln>
    <rex "[^\space]+" $ret>
    <!-- User passwords are our most sensitive data; if a hacker broke
      -- into our web server they could grab the passwd table with all
      -- the passwords if they were stored in the clear.  So we use a
      -- Unix-style one-way encryption: not even this script can decrypt
      -- the user's passwords, only verify them when presented at login:
      -->
    <pwencrypt $ret "">                       <!-- encrypt it -->
    <SQL NOVARS "insert into passwd values(counter, 'admin', $ret,
         'admin,search,insert')">
    </SQL>
    <IF $loop neq 0> admin user created </IF>
  </A>
  
  </SCRIPT>

Let's look at some of what this script does (next page):

Back: Controlled Access Applications Next: Controlled Access Applications - Continued
Copyright © 2024 Thunderstone Software LLC. All rights reserved.