Completed
Push — 4-cactus ( 59c50f...21a27c )
by Alberto
02:40
created

plugins/BEdita/API/src/Auth/UuidAuthenticate.php (1 issue)

1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2017 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\API\Auth;
15
16
use Cake\Auth\BaseAuthenticate;
17
use Cake\Http\Response;
18
use Cake\Http\ServerRequest;
19
use Cake\Network\Exception\UnauthorizedException;
20
use Cake\ORM\TableRegistry;
21
use Cake\Validation\Validation;
22
23
/**
24
 * Anonymously authenticate users by providing a UUID.
25
 *
26
 * Users can authenticate to the server by providing an UUID in the request headers:
27
 *
28
 * ```
29
 * Authorization: UUID 485fc381-e790-47a3-9794-1337c0a8fe68
30
 * ```
31
 *
32
 * @since 4.0.0
33
 */
34
class UuidAuthenticate extends BaseAuthenticate
35
{
36
37
    /**
38
     * Default config for this object.
39
     *
40
     * - `authProviders` The AuthProviders entities associated to this authentication component.
41
     *      Array formatted with `auth_providers.name` as key, from `AuthProvidersTable::findAuthenticate()`
42
     * - `header` The header where the token is stored. Defaults to `'Authorization'`.
43
     * - `headerPrefix` The prefix to the token in header. Defaults to `'UUID'`.
44
     * - `fields` The fields to use to identify a user by.
45
     * - `userModel` The alias for users table, defaults to Users.
46
     * - `finder` The finder method to use to fetch user record. Defaults to 'all'.
47
     *   You can set finder name as string or an array where key is finder name and value
48
     *   is an array passed to `Table::find()` options.
49
     *   E.g. ['finderName' => ['some_finder_option' => 'some_value']]
50
     * - `passwordHasher` Password hasher class. Can be a string specifying class name
51
     *    or an array containing `className` key, any other keys will be passed as
52
     *    config to the class. Defaults to 'Default'.
53
     * - Options `scope` and `contain` have been deprecated since 3.1. Use custom
54
     *   finder instead to modify the query to fetch user record.
55
     *
56
     * @var array
57
     */
58
    protected $_defaultConfig = [
59
        'authProviders' => [],
60
        'header' => 'Authorization',
61
        'headerPrefix' => 'UUID',
62
        'fields' => [
63
            'username' => 'ExternalAuth.provider_username',
64
            'password' => null,
65
        ],
66
        'userModel' => 'Users',
67
        'scope' => [],
68
        'finder' => 'all',
69
        'contain' => null,
70
        'passwordHasher' => 'Default',
71
    ];
72
73
    /**
74
     * Find a user by UUID.
75
     *
76
     * @param string $username UUID.
77
     * @param null $password Password.
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
78
     * @return array|bool
79
     */
80
    protected function _findUser($username, $password = null)
81
    {
82
        $authProvider = collection($this->_config['authProviders'])->first();
83
        $this->setConfig('finder', [
84
            'externalAuth' => [
85
                'auth_provider' => $authProvider
86
            ],
87
        ]);
88
89
        $externalAuth = parent::_findUser($username, $password);
90
        if (!empty($externalAuth)) {
91
            return $externalAuth;
92
        }
93
94
        $Table = TableRegistry::get($this->_config['userModel']);
95
        $providerUsername = $username;
96
        $Table->dispatchEvent('Auth.externalAuth', compact('authProvider', 'providerUsername'));
97
98
        return parent::_findUser($username, $password);
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     */
104
    public function authenticate(ServerRequest $request, Response $response)
105
    {
106
        return $this->getUser($request);
107
    }
108
109
    /**
110
     * {@inheritDoc}
111
     */
112
    public function getUser(ServerRequest $request)
113
    {
114
        $token = $this->getToken($request);
115
        if ($token) {
116
            return $this->_findUser($token);
117
        }
118
119
        return false;
120
    }
121
122
    /**
123
     * Obtain the token from request headers.
124
     *
125
     * @param \Cake\Http\ServerRequest $request Request object.
126
     * @return false|string
127
     */
128
    public function getToken(ServerRequest $request)
129
    {
130
        $header = $request->getHeaderLine($this->_config['header']);
131
        if (!$header) {
132
            return false;
133
        }
134
135
        $prefix = $this->_config['headerPrefix'] . ' ';
136
        if (strpos($header, $prefix) !== 0) {
137
            return false;
138
        }
139
140
        $token = substr($header, strlen($prefix));
141
        if (!Validation::uuid($token)) {
142
            return false;
143
        }
144
145
        return $token;
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151
    public function unauthenticated(ServerRequest $request, Response $response)
152
    {
153
        $message = $this->_registry->getController()->Auth->getConfig('authError');
154
        throw new UnauthorizedException($message);
155
    }
156
}
157