Pdo   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 5
dl 0
loc 124
ccs 33
cts 33
cp 1
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A execute() 0 6 1
A getSql() 0 8 2
A fetchResult() 0 9 3
A login() 0 16 2
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Caridea
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
 * use this file except in compliance with the License. You may obtain a copy of
8
 * the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
 * License for the specific language governing permissions and limitations under
16
 * the License.
17
 *
18
 * @copyright 2015-2018 LibreWorks contributors
19
 * @license   Apache-2.0
20
 */
21
namespace Caridea\Auth\Adapter;
22
23
use \Psr\Http\Message\ServerRequestInterface;
24
25
/**
26
 * PDO authentication adapter.
27
 *
28
 * @copyright 2015-2018 LibreWorks contributors
29
 * @license   Apache-2.0
30
 */
31
class Pdo extends AbstractAdapter
32
{
33
    /**
34
     * @var \PDO The database connection
35
     */
36
    protected $pdo;
37
    /**
38
     * @var string The document field containing the username
39
     */
40
    protected $fieldUser;
41
    /**
42
     * @var string The document field containing the password
43
     */
44
    protected $fieldPass;
45
    /**
46
     * @var string The table (and possible JOINs) from which to SELECT
47
     */
48
    protected $table;
49
    /**
50
     * @var string Any additional WHERE parameters
51
     */
52
    protected $where;
53
    
54
    /**
55
     * Creates a new PDO authentication adapter.
56
     *
57
     * @param \PDO $pdo The PDO driver
58
     * @param string $fieldUser The document field containing the username
59
     * @param string $fieldPass The document field containing the hashed password
60
     * @param string $table The table (and possible JOINs) from which to SELECT
61
     * @param string $where Any additional WHERE parameters (e.g. "foo = 'bar'")
62
     */
63 5
    public function __construct(\PDO $pdo, string $fieldUser, string $fieldPass, string $table, string $where = '')
64
    {
65 5
        $this->pdo = $pdo;
66 5
        $this->fieldUser = $this->checkBlank($fieldUser, "username");
67 5
        $this->fieldPass = $this->checkBlank($fieldPass, "password");
68 5
        $this->table = $this->checkBlank($table, "table");
69 5
        $this->where = $where;
70 5
    }
71
    
72
    /**
73
     * Authenticates the current principal using the provided credentials.
74
     *
75
     * This method expects two request body values to be available. These are
76
     * `username` and `password`, as provided by the authenticating user.
77
     *
78
     * The principal details will include `ip` (remote IP address), and `ua`
79
     * (remote User Agent).
80
     *
81
     * @param ServerRequestInterface $request The Server Request message containing credentials
82
     * @return \Caridea\Auth\Principal An authenticated principal
83
     * @throws \Caridea\Auth\Exception\MissingCredentials If the username or password is empty
84
     * @throws \Caridea\Auth\Exception\UsernameNotFound if the provided username wasn't found
85
     * @throws \Caridea\Auth\Exception\UsernameAmbiguous if the provided username matches multiple accounts
86
     * @throws \Caridea\Auth\Exception\InvalidPassword if the provided password is invalid
87
     * @throws \Caridea\Auth\Exception\ConnectionFailed if a PDO error is encountered
88
     */
89 5
    public function login(ServerRequestInterface $request): \Caridea\Auth\Principal
90
    {
91 5
        $post = (array) $request->getParsedBody();
92 5
        $username = $this->ensure($post, 'username');
93
        try {
94 5
            $stmt = $this->execute($username, $request);
95 4
            $row = $this->fetchResult($stmt->fetchAll(\PDO::FETCH_NUM), $username);
96 2
            $this->verify($this->ensure($post, 'password'), $row[1]);
97 1
            return \Caridea\Auth\Principal::get(
98 1
                $username,
99 1
                $this->details($request, [])
100
            );
101 4
        } catch (\PDOException $e) {
102 1
            throw new \Caridea\Auth\Exception\ConnectionFailed($e);
103
        }
104
    }
105
    
106
    /**
107
     * Queries the database table.
108
     *
109
     * Override this method if you want to bind additonal values to the SQL
110
     * query.
111
     *
112
     * @param string $username The username to use for parameter binding
113
     * @param ServerRequestInterface $request The Server Request message (to use for additional parameter binding)
114
     */
115 5
    protected function execute(string $username, ServerRequestInterface $request): \PDOStatement
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
116
    {
117 5
        $stmt = $this->pdo->prepare($this->getSql());
118 4
        $stmt->execute([$username]);
119 4
        return $stmt;
120
    }
121
    
122
    /**
123
     * Builds the SQL query to be executed.
124
     *
125
     * @return string The SQL query
126
     */
127 1
    protected function getSql(): string
128
    {
129 1
        $sql = "SELECT {$this->fieldUser}, {$this->fieldPass} FROM {$this->table} WHERE {$this->fieldUser} = ?";
130 1
        if ($this->where) {
131 1
            $sql .= " AND ({$this->where})";
132
        }
133 1
        return $sql;
134
    }
135
    
136
    /**
137
     * Fetches a single result from the database resultset.
138
     *
139
     * @param array $results The results as returned from `fetchAll`
140
     * @param string $username The attempted username (for Exception purposes)
141
     * @return array A single database result
142
     * @throws \Caridea\Auth\Exception\UsernameAmbiguous If there is more than 1 result
143
     * @throws \Caridea\Auth\Exception\UsernameNotFound If there are 0 results
144
     */
145 4
    protected function fetchResult(array $results, string $username): array
146
    {
147 4
        if (count($results) > 1) {
148 1
            throw new \Caridea\Auth\Exception\UsernameAmbiguous($username);
149 3
        } elseif (count($results) == 0) {
150 1
            throw new \Caridea\Auth\Exception\UsernameNotFound($username);
151
        }
152 2
        return current($results);
153
    }
154
}
155