You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
5.2 KiB

3 years ago
  1. <?php
  2. /**
  3. * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Roeland Jago Douma <roeland@famdouma.nl>
  7. * @author Tim Obert <tobert@w-commerce.de>
  8. * @author TimObert <tobert@w-commerce.de>
  9. *
  10. * @license GNU AGPL version 3 or any later version
  11. *
  12. * This program is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU Affero General Public License as
  14. * published by the Free Software Foundation, either version 3 of the
  15. * License, or (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. *
  25. */
  26. declare(strict_types=1);
  27. namespace OCP\AppFramework;
  28. use OCP\AppFramework\Http\RedirectResponse;
  29. use OCP\AppFramework\Http\TemplateResponse;
  30. use OCP\IRequest;
  31. use OCP\ISession;
  32. use OCP\IURLGenerator;
  33. /**
  34. * Base controller for interactive public shares
  35. *
  36. * It will verify if the user is properly authenticated to the share. If not the
  37. * user will be redirected to an authentication page.
  38. *
  39. * Use this for a controller that is to be called directly by a user. So the
  40. * normal public share page for files/calendars etc.
  41. *
  42. * @since 14.0.0
  43. */
  44. abstract class AuthPublicShareController extends PublicShareController {
  45. /** @var IURLGenerator */
  46. protected $urlGenerator;
  47. /**
  48. * @since 14.0.0
  49. */
  50. public function __construct(string $appName,
  51. IRequest $request,
  52. ISession $session,
  53. IURLGenerator $urlGenerator) {
  54. parent::__construct($appName, $request, $session);
  55. $this->urlGenerator = $urlGenerator;
  56. }
  57. /**
  58. * @PublicPage
  59. * @NoCSRFRequired
  60. *
  61. * Show the authentication page
  62. * The form has to submit to the authenticate method route
  63. *
  64. * @since 14.0.0
  65. */
  66. public function showAuthenticate(): TemplateResponse {
  67. return new TemplateResponse('core', 'publicshareauth', [], 'guest');
  68. }
  69. /**
  70. * The template to show when authentication failed
  71. *
  72. * @since 14.0.0
  73. */
  74. protected function showAuthFailed(): TemplateResponse {
  75. return new TemplateResponse('core', 'publicshareauth', ['wrongpw' => true], 'guest');
  76. }
  77. /**
  78. * Verify the password
  79. *
  80. * @since 14.0.0
  81. */
  82. abstract protected function verifyPassword(string $password): bool;
  83. /**
  84. * Function called after failed authentication
  85. *
  86. * You can use this to do some logging for example
  87. *
  88. * @since 14.0.0
  89. */
  90. protected function authFailed() {
  91. }
  92. /**
  93. * Function called after successfull authentication
  94. *
  95. * You can use this to do some logging for example
  96. *
  97. * @since 14.0.0
  98. */
  99. protected function authSucceeded() {
  100. }
  101. /**
  102. * @UseSession
  103. * @PublicPage
  104. * @BruteForceProtection(action=publicLinkAuth)
  105. *
  106. * Authenticate the share
  107. *
  108. * @since 14.0.0
  109. */
  110. final public function authenticate(string $password = '') {
  111. // Already authenticated
  112. if ($this->isAuthenticated()) {
  113. return $this->getRedirect();
  114. }
  115. if (!$this->verifyPassword($password)) {
  116. $this->authFailed();
  117. $response = $this->showAuthFailed();
  118. $response->throttle();
  119. return $response;
  120. }
  121. $this->session->regenerateId(true, true);
  122. $response = $this->getRedirect();
  123. $this->session->set('public_link_authenticated_token', $this->getToken());
  124. $this->session->set('public_link_authenticated_password_hash', $this->getPasswordHash());
  125. $this->authSucceeded();
  126. return $response;
  127. }
  128. /**
  129. * Default landing page
  130. *
  131. * @since 14.0.0
  132. */
  133. abstract public function showShare(): TemplateResponse;
  134. /**
  135. * @since 14.0.0
  136. */
  137. final public function getAuthenticationRedirect(string $redirect): RedirectResponse {
  138. return new RedirectResponse(
  139. $this->urlGenerator->linkToRoute($this->getRoute('showAuthenticate'), ['token' => $this->getToken(), 'redirect' => $redirect])
  140. );
  141. }
  142. /**
  143. * @since 14.0.0
  144. */
  145. private function getRoute(string $function): string {
  146. $app = strtolower($this->appName);
  147. $class = (new \ReflectionClass($this))->getShortName();
  148. if (substr($class, -10) === 'Controller') {
  149. $class = substr($class, 0, -10);
  150. }
  151. return $app .'.'. $class .'.'. $function;
  152. }
  153. /**
  154. * @since 14.0.0
  155. */
  156. private function getRedirect(): RedirectResponse {
  157. //Get all the stored redirect parameters:
  158. $params = $this->session->get('public_link_authenticate_redirect');
  159. $route = $this->getRoute('showShare');
  160. if ($params === null) {
  161. $params = [
  162. 'token' => $this->getToken(),
  163. ];
  164. } else {
  165. $params = json_decode($params, true);
  166. if (isset($params['_route'])) {
  167. $route = $params['_route'];
  168. unset($params['_route']);
  169. }
  170. // If the token doesn't match the rest of the arguments can't be trusted either
  171. if (isset($params['token']) && $params['token'] !== $this->getToken()) {
  172. $params = [
  173. 'token' => $this->getToken(),
  174. ];
  175. }
  176. // We need a token
  177. if (!isset($params['token'])) {
  178. $params = [
  179. 'token' => $this->getToken(),
  180. ];
  181. }
  182. }
  183. return new RedirectResponse($this->urlGenerator->linkToRoute($route, $params));
  184. }
  185. }