diff --git a/include/class.auth.php b/include/class.auth.php index e3bce85fe5b83f8e5c11c626ac6115845a185a18..400070ab420691769eaf158788a2da723c87a9c6 100644 --- a/include/class.auth.php +++ b/include/class.auth.php @@ -749,4 +749,38 @@ class AuthTokenAuthentication extends UserAuthenticationBackend { } UserAuthenticationBackend::register(AuthTokenAuthentication); +//Simple ticket lookup backend used to recover ticket access link. +// We're using authentication backend so we can guard aganist brute force +// attempts (which doesn't buy much since the link is emailed) +class AccessLinkAuthentication extends UserAuthenticationBackend { + static $name = "Ticket Access Link Authentication"; + static $id = "authlink"; + + function authenticate($email, $number) { + + if (!($ticket = Ticket::lookupByNumber($number)) + || !($user=User::lookup(array('emails__address' => + $email)))) + return false; + + //Ticket owner? + if ($ticket->getUserId() == $user->getId()) + $user = $ticket->getOwner(); + //Collaborator? + elseif (!($user = Collaborator::lookup(array('userId' => + $user->getId(), 'ticketId' => + $ticket->getId())))) + return false; //Bro, we don't know you! + + + return new ClientSession($user); + } + + //We are not actually logging in the user.... + function login($user, $bk) { + return true; + } + +} +UserAuthenticationBackend::register(AccessLinkAuthentication); ?> diff --git a/include/class.client.php b/include/class.client.php index 93aa1b07f0b978f6a11fdfa64eb25b3b62de7808..e9567c68fdd3d0901a617f574fab24b43753592a 100644 --- a/include/class.client.php +++ b/include/class.client.php @@ -44,6 +44,24 @@ abstract class TicketUser { } + function sendAccessLink() { + global $ost; + + if (!($ticket = $this->getTicket()) + || !($dept = $ticket->getDept()) + || !($email = $dept->getAutoRespEmail()) + || !($tpl = $dept->getTemplate()->getMsgTemplate('user.accesslink'))) + return; + + $vars = array( + 'url' => $ost->getConfig()->getBaseUrl(), + 'ticket' => $this->getTicket(), + 'recipient' => $this); + + $msg = $ost->replaceTemplateVariables($tpl->asArray(), $vars); + $email->send($this->getEmail(), $msg['subj'], $msg['body']); + } + protected function getAuthToken($algo=1) { //Format: // <user type><algo id used>x<pack of uid & tid><hash of the algo> diff --git a/include/class.template.php b/include/class.template.php index 440719db4187b3dae96b5e58b8d643824cba9efd..88f3e5c5701383cca67b68f55764d0f30eb92262 100644 --- a/include/class.template.php +++ b/include/class.template.php @@ -82,8 +82,11 @@ class EmailTemplateGroup { 'staff.pwreset' => array( 'group'=>'sys', 'name' => 'Staff Password Reset', - 'desc' => 'Notice sent to staff with the password reset link.', - 'default' => 'templates/staff.pwreset.txt'), + 'desc' => 'Notice sent to staff with the password reset link.'), + 'user.accesslink' => array( + 'group'=>'sys', + 'name' => 'User Access Link Recovery', + 'desc' => 'Notice sent to user on request with ticket access link.'), ); function EmailTemplateGroup($id){ diff --git a/include/client/login.inc.php b/include/client/login.inc.php index 7e46c2eb30598e2220128654b0232cd08d81ac62..586ef9808b75144e37dafc775debb9cc8f4ca1c4 100644 --- a/include/client/login.inc.php +++ b/include/client/login.inc.php @@ -5,7 +5,8 @@ $email=Format::input($_POST['lemail']?$_POST['lemail']:$_GET['e']); $ticketid=Format::input($_POST['lticket']?$_POST['lticket']:$_GET['t']); ?> <h1>Check Ticket Status</h1> -<p>To view the status of a ticket, provide us with the login details below.</p> +<p>Please provide us with your email address and a ticket number, and an access +link will be emailed to you.</p> <form action="login.php" method="post" id="clientLogin"> <?php csrf_token(); ?> <strong><?php echo Format::htmlchars($errors['login']); ?></strong> @@ -15,14 +16,14 @@ $ticketid=Format::input($_POST['lticket']?$_POST['lticket']:$_GET['t']); <input id="email" type="text" name="lemail" size="30" value="<?php echo $email; ?>"> </div> <div> - <label for="ticketno">Ticket ID:</label> + <label for="ticketno">Ticket Number:</label> <input id="ticketno" type="text" name="lticket" size="16" value="<?php echo $ticketid; ?>"></td> </div> <p> - <input class="btn" type="submit" value="View Status"> + <input class="btn" type="submit" value="Email Access Link"> </p> </form> <br> <p> -If this is your first time contacting us or you've lost the ticket ID, please <a href="open.php">open a new ticket</a>. +If this is your first time contacting us or you've lost the ticket number, please <a href="open.php">open a new ticket</a>. </p> diff --git a/include/i18n/en_US/templates/email/user.accesslink.yaml b/include/i18n/en_US/templates/email/user.accesslink.yaml new file mode 100644 index 0000000000000000000000000000000000000000..acd50fe0fd5b9c89b9efffffa72e271b85491f0e --- /dev/null +++ b/include/i18n/en_US/templates/email/user.accesslink.yaml @@ -0,0 +1,32 @@ +# +# Email template: user.accesslink +# +# Sent when a user requests an access link to check the status of a ticket +# +# +# +--- +notes: | + Sent when a user requests an access link to check the status of a ticket + +subject: | + Ticket [#%{ticket.number}] Access Link +body: | + <h3><strong>Hi %{recipient.name.first},</strong></h3> + An access link request for ticket #%{ticket.number} has been submitted on your behalf for the + helpdesk at %{url}. + <br> + <br> + Follow the link below to check the status of the ticket #%{ticket.number}. + <br> + <br> + <a href="%{recipient.ticket_link}">%{recipient.ticket_link}</a> + <br> + <br>If you <strong>did not</strong> make the request, please delete + and disregard this email. Your account is still secure and no one has + been given access to the ticket. Someone could have mistakenly entered + your email address. + <br> + <br> + --<br> + %{company.name} diff --git a/login.php b/login.php index 435eebd93a03e7f4f7d1b75509e3c1685b627a02..9e6d5f36f18d64384f96818ae82498a774553344 100644 --- a/login.php +++ b/login.php @@ -2,7 +2,10 @@ /********************************************************************* login.php - Client Login + User access link recovery + + TODO: This is a temp. fix to allow for collaboration in lieu of real + username and password coming in 1.8.2 Peter Rotich <peter@osticket.com> Copyright (c) 2006-2013 osTicket @@ -21,21 +24,26 @@ define('OSTCLIENTINC',TRUE); //make includes happy require_once(INCLUDE_DIR.'class.client.php'); require_once(INCLUDE_DIR.'class.ticket.php'); +$inc = 'login.inc.php'; if ($_POST) { - if (($user = UserAuthenticationBackend::process($_POST['lemail'], + if (!$_POST['lticket'] || !Validator::is_email($_POST['lemail'])) + $errors['err'] = 'Valid email address and ticket number required'; + elseif (($user = UserAuthenticationBackend::process($_POST['lemail'], $_POST['lticket'], $errors))) { - //XXX: Ticket owner is assumed. - @header('Location: tickets.php?id='.$user->getTicketId()); - require_once('tickets.php'); //Just in case of 'header already sent' error. - exit; + //We're using authentication backend so we can guard aganist brute + // force attempts (which doesn't buy much since the link is emailed) + $user->sendAccessLink(); + $msg = sprintf("%s - access link sent to your email!", + $user->getName()->getFirst()); + $_POST = null; } elseif(!$errors['err']) { - $errors['err'] = 'Authentication error - try again!'; + $errors['err'] = 'Invalid email or ticket number - try again!'; } } $nav = new UserNav(); $nav->setActiveNav('status'); -require(CLIENTINC_DIR.'header.inc.php'); -require(CLIENTINC_DIR.'login.inc.php'); -require(CLIENTINC_DIR.'footer.inc.php'); +require CLIENTINC_DIR.'header.inc.php'; +require CLIENTINC_DIR.$inc; +require CLIENTINC_DIR.'footer.inc.php'; ?>