• User

    [TUTORIAL]Creare una webmail registrando online gli utenti

    Salve siccome sto affrontando un piccolo problema, ovvero quello di creare una webmail interna alla mia azienda, usando un mta che gira su Windows (MercuryMail) e poichè ho trovato la quadra del cerchio, scrivo questo
    tutorial in modo che se altri si trovassero ad affrontare il mio stesso problema possano trovare uno spunto inziale.

    PARTE UNO: CONFIGURAZIONE

    **Di cosa tratta questo tutorial ? **
    Questo tutorial tratta degli aspetti legati alla scrittura di una form online che contemporaneamente crei un nuovo utente al interno di MercuryMail e del database associato inviando nel contempo una mail di conferma al
    utente che, rispondendo a tale mail, può attivare l'account.

    Di cosa non tratta questo tutorial ?
    Di tutti quelli aspetti legati alla gestione delle funzioni mail e imap. In pratica in questo tutorial, forse in uno seguente si, non vedremo come scrivere una classe per inviare e ricevere la posta, gestire formati ed allegati ma
    solamente come creare un form per la registrazione degli utenti valido anche per l'mta sottostante.

    Una precisazione
    Quando un utente si registra in MercuryMail gli vengono creati:

    • una directory corrispondente al suo nome (es: utente = Pluto, directory = Pluto) al interno della cartella MercuryMail\Mail
    • un file di nome PASSWORD.PM al interno di MercuryMail\Pluto
    • una voce nel file degli alias (alias.src) che si trova in MercuryMail

    Tali dati creati fanno si che l'utente possa da subito iniziare a inviare e ricevere mail seppur nella finestra di gestione "LocalUser" del pannello di controllo di MercuryMail tali utenti non compaiano fino al prossimo riavvio
    dello stesso; riavvio che può essere impostato ogni tot di tempo semplicemente configurandolo come servizio e agendo sulle impostazioni di Windows e quindi soggettivo delle necessità personali. Il mancato riavvio,
    con la conseguente mancata visualizzazione, non esclude però che la webmail sia stata creata e men che meno che non sia da subito utilizzabile.

    Cenni preliminari
    Personalmente ho installato MercuryMail assieme a xampp quindi mi sono trovato con la seguente struttura:

    • c:\xampp\MercuryMail
    • c:\xampp\MercuryMail\Mail

    Ne consegue che quando farò riferimento ai path a cui accedere per le specifiche locazioni i miei saranno:

    • Cartella principale: c:\xampp\MercuryMail
    • Cartella utenti : c:\xampp\MercuryMail\Mail
    • Cartella file di alias: -> Cartella Principale

    Inoltre i path di ricerca per il server di posta, a meno che non abbiate un dns interno, saranno sempre localhost
    **
    Operazioni preliminari**
    Di default MercuryMail è configurato per scrivere la posta su disco mediante un programma chiamato mailtodisk.exe è quindi necessario agire sul file di configurazione di php (php.ini) per commentare la riga di riferimento a mailtodisk.exe e decommentare quella di riferimento a sendmail riavviando poi apache.

    [php]

    /**
    *

    • Questa prima direttiva è di default commentata su molte versioni di Windows.
    • Per attivarla è necessario levargli il punto e virgola che la precede

    */
    ; For Win32 only.
    sendmail_from = postmaster@localhost

    /**
    *

    • Qua bisogna lasciare tutto come sta

    */
    ; XAMPP IMPORTANT NOTE (1): If XAMPP is installed in a base directory with spaces (e.g. c:\program filesC:\xampp) fakemail and mailtodisk do not work correctly.
    ; XAMPP IMPORTANT NOTE (2): In this case please copy the sendmail or mailtodisk folder in your root folder (e.g. C:\sendmail) and use this for sendmail_path.

    ; XAMPP: Comment out this if you want to work with fakemail for forwarding to your mailbox (sendmail.exe in the sendmail folder)
    ;sendmail_path = ""C:\xampp\sendmail\sendmail.exe" -t"

    /**
    *

    • Questa direttiva, invece, è di default attiva. Commentatela facendola precedere dal punto e virgola.

    */
    ; XAMPP: Comment out this if you want to work with mailToDisk, It writes all mails in the C:\xampp\mailoutput folder
    ; sendmail_path = "C:\xampp\mailtodisk\mailtodisk.exe"

    [/php]

    Al termine di queste eperazioni riavviate apache.

    **Testiamo la configurazione
    **Adesso che abbiamo fatto questo non ci resta che accedere al pannello di controllo di MercuryMail e di li menù: Configuration->Manage local users... e creare un nuovo utente cliccando sulla voce add

    Fatto questo possiamo procedere ad inviare una semplice mail di prova in questo modo

    1. Inviamo una mail usando la funzione mail di php

    [php]
    <?php
    /**
    *

    • tuonome va sostituito con il nome della casella di posta

    */
    mail ("tuonome@localhost", "Prova", "Questa è una prova");

    ?>
    [/php]

    1. Aspettiamo un paio di secondi poi rechiamoci in c:\DoveAveteInstallatoMercuryMail\Mail\NumeUtente\ e vedremo comparire un file composto da 8 caratteri alfanumerici con estensione .CNM
      Nel mio caso il file si chiama: YD61KSTG.CNM e se lo edito con un qualsiasi editor di testo (mi trovo molto bene con notepad++) al suo interno trovo:
    
    Received: from spooler by localhost (Mercury/32 v4.62); 2 Aug 2012 01:55:00 +0200
    X-Envelope-To: <aa1@localhost>
    Return-path: <postmaster@localhost>
    Received: from nabucco-donosor (127.0.0.1) by localhost (Mercury/32 v4.62) ID MG000002;
       2 Aug 2012 01:54:51 +0200
    Date: Thu, 02 Aug 2012 01:54:51 +0200
    From: postmaster@localhost
    Subject: Prova
    To: aa1@localhost
    
    Mail di priva
    
    

    PARTE DUE: LA PAROLA A PHP

    Cenni sulla sicurezza
    Se noi apriamo il file passwd.pm del nostro utente troviamo un qualcosa di simile a questo:

    
    # Mercury/32 User Information File
    POP3_access: PasswordInChiaro
    APOP_secret: PasswordInChiaro
    
    

    che è esattamente ciò che state pensando ovvero la password scritta a chiare lettere; orrore !!!!! se un malintenzionato riuscisse ad accedere al nostro server potrebbe prendersele tutte e, se fossero uguali, avrebbe
    anche quelle degli utenti che accedono al database.

    Gli script originali di MercuryMail, reperibili sul sito ufficiale, prevedono proprio questo ma a noi non ci sta bene quindi qualcosa dobbiamo inventarci.

    La logica dietro alla sicurezza
    La logica che sta dietro alla sicurezza è molto semplice e dice che: **Se tu sei in grado di autenticarti sul mio database con username e password validi allora ti do accesso alla tua WebMail al contrario dopo tre tentativi ti
    blocco l'account.
    **
    Semplice, chiaro ed efficace 🙂

    Per ottenere questo si procede in questo modo:

    1. Si crea un database chiamato WebMail al cui interno va creata la tabella users che contiene i seguent campi:
    • userID
    • userName
    • userPassword
    • realName
    • realSurname
    • activationCode
    • activationSuccess
    • deactivateProgress
    • deactivateAccount

    Il significato dei campi è abbastanza chiaro. Intendiamo registrare un id autoincrementale, una username che sarà anche la username della casella di posta, la password, il nome completo (Nome e Cognome utili per la visualizzazione o per un eventuale pannello di controllo) poi viene creata una sessione e immagazzinata nel database alla voce activationCode mentre il campo activationSuccess viene impostato a 0. Il significato è molto semplice: poichè l'activationCode è quello che viene inviato per mail onde verificare l'account se quello è presente nel database e il campo seguente (activationSuccess) è uguale a 0 l'utente non ha ancora validato la sua iscrizione. deactivataProgress invece viene incrementato con una query update di 1 ogni volta che si sbaglia ad inserire username e password. Quando il suo valore è pari a 3, o numero di tentativi a piacere, automaticamente un'altra query aggiorna il campo deactivateAccount bloccando di fatto l'account del utente che deve richiedere l'intervento di un admin per sbloccarlo.

    1. Si crea uno script come il seguente:

    NOTA: Tutti i codici presentati sono molto minimali. Ho scelto questa soluzione, seppur per le mie esigenze abbia scritto delle classi, in quanto questo è un tutorial aperto a qualsiasi livello di esperienza. Chiunque è libero di riorganizzarsi il codice come meglio crede.

    index.html
    [php]
    <form method="post" action="registraUtente.php">
    Username: <input type="text" name="userName"><br />
    Password: <input type="password" name="userPassword"><br />
    Conferma Password: <input type="password" name="password2"><br />
    Nome Reale <input type="text" name="realName"><br />
    Cognome Reale <input type="text" name="realSurname"><br />
    <input type="submit" name="Invia">
    </form>
    [/php]

    Come si vede la form è molto semplice e non fa altro che chiedere uno username, una password, che venga riscritta la password, il nome reale e il cognome reale. La validazione dei campi non è materia di questo tutorial e do per assunto che chiunque sia in grado di farla per conto suo.

    registraUtente.php
    [php]
    <?php

    session_start();

    /**
    *

    • Si da per assunto che i campi siano già stati validati ed eventualmente ripuliti/trattati in modo opportuno
    • quindi si da per assunto che nessun campo sia vuoto, se marcato come richiesto, che la password immesse
    • siano uguali e per finire che lo username che l'utente cerca di registrare non esista già nel database.

    */

    // Per prima cosa convertiamo un pò di variabili
    $username = $_POST['userName'];
    $password = md5($_POST['userPassword'];
    $realname = $_POST['realName'];
    $realsurname = $_POST['realSurname'];
    $activation = session_id();

    // Definiamo la connessione al database
    $host = 'localhost';
    $user = 'tuoUser';
    $pass = 'tuaPass';
    $db = 'tuoDB';

    /**
    *

    • E registriamo l'utente

    */
    $linkID = mysql_connect ($host, $user, $pass) or die ( 'Errore: Numero di errore - ' . ' ' . mysql_errno() . ' ' . '/' . 'Testo del errore: ' . ' ' . mysql_error() );
    mysql_select_db ( $db, $linkID ) or die ( 'Errore: Numero di errore - ' . ' ' . mysql_errno() . ' ' . '/' . 'Testo del errore: ' . ' ' . mysql_error() );
    $sql = "INSERT INTO users ( 'userName', 'userPassword', 'realName', 'realSurname', 'activationCode', 'activationSuccess' ) VALUES ( $username, $password, $realname, $realsurname, $activation, 0 )";
    mysql_query($sql);

    /**
    *

    • Inserire qua i controlli per verificare l'esistenza della directory utente e del file password.pm al suo interno e, nel caso, per cancellarli.

    */

    // Ricordo che i path possono variare da installazione a installazione
    $dir = 'c:\xampp\MercuryMail\Mail\' . $username . '\';
    // Qua avviene la creazione della directory destinata a contenere le mail del utente e il suo file di password
    mkdir($dir);

    /**
    *

    • E' possibile inserire, dopo la creazione della directory un controllo del tipo is_dir o is_file per verificare
    • la sua effettiva esistenza

    */

    /**
    *

    • Adesso dobbiamo creare il file passw d.pm al interno del quale mettere la password criptata in md5

    */
    $line1 = '# Mercury/32 User Information File';
    $line2 = 'POP3_access: ' . $password;
    $line3 = 'APOP_secret: ' . $password;
    // Ricordo ancora una volta che i path possono variare
    $filename = 'c:\xampp\MercuryMail\mail\' . $username . '\passwd.pm';
    // Apriamo il file passwd.pm in scrittura e se non c'è lo si crea
    $handle = fopen($filename, "w");
    if ($handle) {
    fwrite($handle, $line1 . chr(10));
    fwrite($handle, $line2 . chr(10));
    fwrite($handle, $line3 . chr(10));
    fclose($handle);
    }

    /**
    *

    • Creiamo l'alias
    • Attenzione per attivare questa funzione è necessrio fare due cose:
      1. Creare una form per permettere al utente di crearsi autonomamente un alias
      1. Creare una form nel pannello di controllo admin per permettere la creazione di un alias
    • In ogni caso se $_POST['alias'] non è settata l'alias è la mail originale sono uguali
    • In pratica se l'alias è settato si compone una stringa del tipo alias@dominio == username@dominio
    • e dopo viene registrato nel file degli alias. Se non lo è si compone username@dominio == username@dominio
    • e viene registrato questo

    */
    if ( isset ( $_POST['alias'] ) )
    {
    $alias = $_POST['alias'] . '@' . $domain;
    $mail = $username . '@' . $domain;
    $line = $alias . ' == ' . $mail;
    return $line;
    } else {
    $mail = $username . '@' . $domain;
    $line = $mail . '==' . $mail;
    return $line;
    }
    // Apriamo il file e ci scriviamo dentro
    $filename = 'c:\xampp\MercuryMail\alias.src';
    $handle = fopen($filename, "a"); // usiamo a per appendere la riga alla fine del file
    if ($handle) {
    fwrite($handle, $line . chr(10));
    fclose($handle);
    }

    /**
    *

    • Adesso non resta che mandare una mail al utente per verificare l'account

    */
    function autenticate($username, $_POST['userPassword'], $realname, $realsurname, $activationCode)
    {

          /**
           *
           *  Codice per inviare la mail
           *
           */
    

    }

    autenticate($username, $_POST['userPassword'], $realname, $realsurname, $activationCode);

    /**
    *

    • E mandiamo anche la mail al sistema per la registrazione del account
    • Questo spezzone di codice è tratto dagli script originali.

    */
    $to="maiser@localhost";
    $subject=".";
    $header="From: administrator@localhost";
    $message="
    password pass
    reload users
    exit
    ";
    //ini_set('sendmail_from', '[email protected]');
    $sentmail = mail($to,$subject,$message,$header);
    if($sentmail){
    $email_sent = 'y';
    } else {
    $email_sent = 'n';
    }

    [/php]

    Ecco fatto. Se tutto è andato bene avete:

    • Registrato l'utente nel database in modo sicuro
    • Creto l'utente in MercuryMail
    • Associato ad esso una password sicura, quindi non più in chiaro come in originale alla quale accedere poi dalle funzioni imap
    • Creato un alias
    • Inviato una mail al utente per attivare l'account
    • Inviato una mail di attivazione al sistema
    • Riletto la tavola degli utenti.

    E' tutto. Al prossimo tutorial