Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   1  <?php
   2  
   3  /**
   4   * Licensed to Jasig under one or more contributor license
   5   * agreements. See the NOTICE file distributed with this work for
   6   * additional information regarding copyright ownership.
   7   *
   8   * Jasig licenses this file to you under the Apache License,
   9   * Version 2.0 (the "License"); you may not use this file except in
  10   * compliance with the License. You may obtain a copy of the License at:
  11   *
  12   * http://www.apache.org/licenses/LICENSE-2.0
  13   *
  14   * Unless required by applicable law or agreed to in writing, software
  15   * distributed under the License is distributed on an "AS IS" BASIS,
  16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17   * See the License for the specific language governing permissions and
  18   * limitations under the License.
  19   *
  20   * PHP Version 5
  21   *
  22   * @file     CAS/ProxiedService/Imap.php
  23   * @category Authentication
  24   * @package  PhpCAS
  25   * @author   Adam Franco <afranco@middlebury.edu>
  26   * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
  27   * @link     https://wiki.jasig.org/display/CASC/phpCAS
  28   */
  29  
  30  /**
  31   * Provides access to a proxy-authenticated IMAP stream
  32   *
  33   * @class    CAS_ProxiedService_Imap
  34   * @category Authentication
  35   * @package  PhpCAS
  36   * @author   Adam Franco <afranco@middlebury.edu>
  37   * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
  38   * @link     https://wiki.jasig.org/display/CASC/phpCAS
  39   */
  40  class CAS_ProxiedService_Imap
  41  extends CAS_ProxiedService_Abstract
  42  {
  43  
  44      /**
  45       * The username to send via imap_open.
  46       *
  47       * @var string $_username;
  48       */
  49      private $_username;
  50  
  51      /**
  52       * Constructor.
  53       *
  54       * @param string $username Username
  55       *
  56       * @return void
  57       */
  58      public function __construct ($username)
  59      {
  60          if (!is_string($username) || !strlen($username)) {
  61              throw new CAS_InvalidArgumentException('Invalid username.');
  62          }
  63  
  64          $this->_username = $username;
  65      }
  66  
  67      /**
  68       * The target service url.
  69       * @var string $_url;
  70       */
  71      private $_url;
  72  
  73      /**
  74       * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
  75       *
  76       * @return string
  77       * @throws Exception If no service url is available.
  78       */
  79      public function getServiceUrl ()
  80      {
  81          if (empty($this->_url)) {
  82              throw new CAS_ProxiedService_Exception(
  83                  'No URL set via '.get_class($this).'->getServiceUrl($url).'
  84              );
  85          }
  86  
  87          return $this->_url;
  88      }
  89  
  90      /*********************************************************
  91       * Configure the Stream
  92      *********************************************************/
  93  
  94      /**
  95       * Set the URL of the service to pass to CAS for proxy-ticket retrieval.
  96       *
  97       * @param string $url Url to set
  98       *
  99       * @return void
 100       * @throws CAS_OutOfSequenceException If called after the stream has been opened.
 101       */
 102      public function setServiceUrl ($url)
 103      {
 104          if ($this->hasBeenOpened()) {
 105              throw new CAS_OutOfSequenceException(
 106                  'Cannot set the URL, stream already opened.'
 107              );
 108          }
 109          if (!is_string($url) || !strlen($url)) {
 110              throw new CAS_InvalidArgumentException('Invalid url.');
 111          }
 112  
 113          $this->_url = $url;
 114      }
 115  
 116      /**
 117       * The mailbox to open. See the $mailbox parameter of imap_open().
 118       *
 119       * @var string $_mailbox
 120       */
 121      private $_mailbox;
 122  
 123      /**
 124       * Set the mailbox to open. See the $mailbox parameter of imap_open().
 125       *
 126       * @param string $mailbox Mailbox to set
 127       *
 128       * @return void
 129       * @throws CAS_OutOfSequenceException If called after the stream has been opened.
 130       */
 131      public function setMailbox ($mailbox)
 132      {
 133          if ($this->hasBeenOpened()) {
 134              throw new CAS_OutOfSequenceException(
 135                  'Cannot set the mailbox, stream already opened.'
 136              );
 137          }
 138          if (!is_string($mailbox) || !strlen($mailbox)) {
 139              throw new CAS_InvalidArgumentException('Invalid mailbox.');
 140          }
 141  
 142          $this->_mailbox = $mailbox;
 143      }
 144  
 145      /**
 146       * A bit mask of options to pass to imap_open() as the $options parameter.
 147       *
 148       * @var int $_options
 149       */
 150      private $_options = null;
 151  
 152      /**
 153       * Set the options for opening the stream. See the $options parameter of
 154       * imap_open().
 155       *
 156       * @param int $options Options for the stream
 157       *
 158       * @return void
 159       * @throws CAS_OutOfSequenceException If called after the stream has been opened.
 160       */
 161      public function setOptions ($options)
 162      {
 163          if ($this->hasBeenOpened()) {
 164              throw new CAS_OutOfSequenceException(
 165                  'Cannot set options, stream already opened.'
 166              );
 167          }
 168          if (!is_int($options)) {
 169              throw new CAS_InvalidArgumentException('Invalid options.');
 170          }
 171  
 172          $this->_options = $options;
 173      }
 174  
 175      /*********************************************************
 176       * 2. Open the stream
 177      *********************************************************/
 178  
 179      /**
 180       * Open the IMAP stream (similar to imap_open()).
 181       *
 182       * @return resource Returns an IMAP stream on success
 183       * @throws CAS_OutOfSequenceException If called multiple times.
 184       * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
 185       *	 	 The code of the Exception will be one of:
 186       *	 	 	 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
 187       *	 	 	 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
 188       *	 	 	 PHPCAS_SERVICE_PT_FAILURE
 189       * @throws CAS_ProxiedService_Exception If there is a failure sending the
 190       *         request to the target service.
 191       */
 192      public function open ()
 193      {
 194          if ($this->hasBeenOpened()) {
 195              throw new CAS_OutOfSequenceException('Stream already opened.');
 196          }
 197          if (empty($this->_mailbox)) {
 198              throw new CAS_ProxiedService_Exception(
 199                  'You must specify a mailbox via '.get_class($this)
 200                  .'->setMailbox($mailbox)'
 201              );
 202          }
 203  
 204          phpCAS::traceBegin();
 205  
 206          // Get our proxy ticket and append it to our URL.
 207          $this->initializeProxyTicket();
 208          phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\'...');
 209          $this->_stream = @imap_open(
 210              $this->_mailbox, $this->_username, $this->getProxyTicket(),
 211              $this->_options
 212          );
 213          if ($this->_stream) {
 214              phpCAS::trace('ok');
 215          } else {
 216              phpCAS::trace('could not open mailbox');
 217              // @todo add localization integration.
 218              $message = 'IMAP Error: '.$this->_url.' '. var_export(imap_errors(), true);
 219              phpCAS::trace($message);
 220              throw new CAS_ProxiedService_Exception($message);
 221          }
 222  
 223          phpCAS::traceEnd();
 224          return $this->_stream;
 225      }
 226  
 227      /**
 228       * Answer true if our request has been sent yet.
 229       *
 230       * @return bool
 231       */
 232      protected function hasBeenOpened ()
 233      {
 234          return !empty($this->_stream);
 235      }
 236  
 237      /*********************************************************
 238       * 3. Access the result
 239      *********************************************************/
 240      /**
 241       * The IMAP stream
 242       *
 243       * @var resource $_stream
 244       */
 245      private $_stream;
 246  
 247      /**
 248       * Answer the IMAP stream
 249       *
 250       * @return resource
 251       * @throws CAS_OutOfSequenceException if stream is not opened yet
 252       */
 253      public function getStream ()
 254      {
 255          if (!$this->hasBeenOpened()) {
 256              throw new CAS_OutOfSequenceException(
 257                  'Cannot access stream, not opened yet.'
 258              );
 259          }
 260          return $this->_stream;
 261      }
 262  
 263      /**
 264       * CAS_Client::serviceMail() needs to return the proxy ticket for some reason,
 265       * so this method provides access to it.
 266       *
 267       * @return string
 268       * @throws CAS_OutOfSequenceException If called before the stream has been
 269       * opened.
 270       */
 271      public function getImapProxyTicket ()
 272      {
 273          if (!$this->hasBeenOpened()) {
 274              throw new CAS_OutOfSequenceException(
 275                  'Cannot access errors, stream not opened yet.'
 276              );
 277          }
 278          return $this->getProxyTicket();
 279      }
 280  }
 281  ?>