1<?php 2 3namespace Sabre\DAV\Auth; 4 5use Sabre\HTTP\RequestInterface; 6use Sabre\HTTP\ResponseInterface; 7use Sabre\HTTP\URLUtil; 8use Sabre\DAV\Exception\NotAuthenticated; 9use Sabre\DAV\Server; 10use Sabre\DAV\ServerPlugin; 11 12/** 13 * This plugin provides Authentication for a WebDAV server. 14 * 15 * It works by providing a Auth\Backend class. Several examples of these 16 * classes can be found in the Backend directory. 17 * 18 * It's possible to provide more than one backend to this plugin. If more than 19 * one backend was provided, each backend will attempt to authenticate. Only if 20 * all backends fail, we throw a 401. 21 * 22 * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 23 * @author Evert Pot (http://evertpot.com/) 24 * @license http://sabre.io/license/ Modified BSD License 25 */ 26class Plugin extends ServerPlugin { 27 28 /** 29 * authentication backends 30 */ 31 protected $backends; 32 33 /** 34 * The currently logged in principal. Will be `null` if nobody is currently 35 * logged in. 36 * 37 * @var string|null 38 */ 39 protected $currentPrincipal; 40 41 /** 42 * Creates the authentication plugin 43 * 44 * @param Backend\BackendInterface $authBackend 45 */ 46 function __construct(Backend\BackendInterface $authBackend = null) { 47 48 if (!is_null($authBackend)) { 49 $this->addBackend($authBackend); 50 } 51 52 } 53 54 /** 55 * Adds an authentication backend to the plugin. 56 * 57 * @param Backend\BackendInterface $authBackend 58 * @return void 59 */ 60 function addBackend(Backend\BackendInterface $authBackend) { 61 62 $this->backends[] = $authBackend; 63 64 } 65 66 /** 67 * Initializes the plugin. This function is automatically called by the server 68 * 69 * @param Server $server 70 * @return void 71 */ 72 function initialize(Server $server) { 73 74 $server->on('beforeMethod', [$this, 'beforeMethod'], 10); 75 76 } 77 78 /** 79 * Returns a plugin name. 80 * 81 * Using this name other plugins will be able to access other plugins 82 * using DAV\Server::getPlugin 83 * 84 * @return string 85 */ 86 function getPluginName() { 87 88 return 'auth'; 89 90 } 91 92 /** 93 * Returns the currently logged-in principal. 94 * 95 * This will return a string such as: 96 * 97 * principals/username 98 * principals/users/username 99 * 100 * This method will return null if nobody is logged in. 101 * 102 * @return string|null 103 */ 104 function getCurrentPrincipal() { 105 106 return $this->currentPrincipal; 107 108 } 109 110 /** 111 * Returns the current username. 112 * 113 * This method is deprecated and is only kept for backwards compatibility 114 * purposes. Please switch to getCurrentPrincipal(). 115 * 116 * @deprecated Will be removed in a future version! 117 * @return string|null 118 */ 119 function getCurrentUser() { 120 121 // We just do a 'basename' on the principal to give back a sane value 122 // here. 123 list(, $userName) = URLUtil::splitPath( 124 $this->getCurrentPrincipal() 125 ); 126 127 return $userName; 128 129 } 130 131 /** 132 * This method is called before any HTTP method and forces users to be authenticated 133 * 134 * @param RequestInterface $request 135 * @param ResponseInterface $response 136 * @return bool 137 */ 138 function beforeMethod(RequestInterface $request, ResponseInterface $response) { 139 140 if ($this->currentPrincipal) { 141 142 // We already have authentication information. This means that the 143 // event has already fired earlier, and is now likely fired for a 144 // sub-request. 145 // 146 // We don't want to authenticate users twice, so we simply don't do 147 // anything here. See Issue #700 for additional reasoning. 148 // 149 // This is not a perfect solution, but will be fixed once the 150 // "currently authenticated principal" is information that's not 151 // not associated with the plugin, but rather per-request. 152 // 153 // See issue #580 for more information about that. 154 return; 155 156 } 157 if (!$this->backends) { 158 throw new \Sabre\DAV\Exception('No authentication backends were configured on this server.'); 159 } 160 $reasons = []; 161 foreach ($this->backends as $backend) { 162 163 $result = $backend->check( 164 $request, 165 $response 166 ); 167 168 if (!is_array($result) || count($result) !== 2 || !is_bool($result[0]) || !is_string($result[1])) { 169 throw new \Sabre\DAV\Exception('The authentication backend did not return a correct value from the check() method.'); 170 } 171 172 if ($result[0]) { 173 $this->currentPrincipal = $result[1]; 174 // Exit early 175 return; 176 } 177 $reasons[] = $result[1]; 178 179 } 180 181 // If we got here, it means that no authentication backend was 182 // successful in authenticating the user. 183 $this->currentPrincipal = null; 184 185 foreach ($this->backends as $backend) { 186 $backend->challenge($request, $response); 187 } 188 throw new NotAuthenticated(implode(', ', $reasons)); 189 190 } 191 192 /** 193 * Returns a bunch of meta-data about the plugin. 194 * 195 * Providing this information is optional, and is mainly displayed by the 196 * Browser plugin. 197 * 198 * The description key in the returned array may contain html and will not 199 * be sanitized. 200 * 201 * @return array 202 */ 203 function getPluginInfo() { 204 205 return [ 206 'name' => $this->getPluginName(), 207 'description' => 'Generic authentication plugin', 208 'link' => 'http://sabre.io/dav/authentication/', 209 ]; 210 211 } 212 213} 214