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