| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  |  * This file is part of the tiqr project. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  *  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  * The tiqr project aims to provide an open implementation for  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  * authentication using mobile devices. It was initiated by  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  * SURFnet and developed by Egeniq. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  * More information: http://www.tiqr.org | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  * @author Patrick Honing <[email protected]> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  *  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |  * @package tiqr | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  * @license New BSD License - See LICENSE file for details. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |  * @copyright (C) 2010-2012 SURFnet BV | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  *  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |  * Create SQL table (MySQL): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  * CREATE TABLE `tiqrusersecret` (`userid` varchar(10) PRIMARY KEY, `secret` varchar(100)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |  *  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  | use Psr\Log\LoggerInterface; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  * This user storage implementation implements a user secret storage using PDO. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |  * It is usable for any database with a PDO driver | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  *  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |  * @author Patrick Honing <[email protected]> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  * You can create separate tables for Tiqr_UserSecretStorage_Pdo and Tiqr_UserStorage_Pdo | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  * You can also combine the two tables by adding a "secret" column to the user storage table | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |  * @see Tiqr_UserStorage_Pdo | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |  * Mysql Create statement usersecret table | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  | CREATE TABLE IF NOT EXISTS usersecret ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |     id integer NOT NULL PRIMARY KEY AUTO_INCREMENT, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |     userid varchar(30) NOT NULL UNIQUE, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |     secret varchar(128), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  | ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  * @see Tiqr_UserSecretStorage::getSecretStorage() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  * @see Tiqr_UserSecretStorage_Interface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |  * Supported options: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  * path : Path to the directory where the user data is stored | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |  * Supported options: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  * table    : The name of the user table in the database. Optional. Defaults to "tiqrusersecret". | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  * dsn      : The dsn, see the PDO interface documentation | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |  * username : The database username | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |  * password : The database password | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |  */ | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 57 |  |  | class Tiqr_UserSecretStorage_Pdo extends Tiqr_UserSecretStorage_Abstract | 
            
                                                                        
                            
            
                                    
            
            
                | 58 |  |  | { | 
            
                                                                        
                            
            
                                    
            
            
                | 59 |  |  |     private $tableName; | 
            
                                                                        
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 61 |  |  |     private $handle; | 
            
                                                                        
                            
            
                                    
            
            
                | 62 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 63 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 64 |  |  |      * @param Tiqr_UserSecretStorage_Encryption_Interface $encryption | 
            
                                                                        
                            
            
                                    
            
            
                | 65 |  |  |      * @param LoggerInterface $logger | 
            
                                                                        
                            
            
                                    
            
            
                | 66 |  |  |      * @param PDO $handle | 
            
                                                                        
                            
            
                                    
            
            
                | 67 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 68 | 11 |  |     public function __construct( | 
            
                                                                        
                            
            
                                    
            
            
                | 69 |  |  |         Tiqr_UserSecretStorage_Encryption_Interface $encryption, | 
            
                                                                        
                            
            
                                    
            
            
                | 70 |  |  |         LoggerInterface $logger, | 
            
                                                                        
                            
            
                                    
            
            
                | 71 |  |  |         PDO $handle, | 
            
                                                                        
                            
            
                                    
            
            
                | 72 |  |  |         string $tableName, | 
            
                                                                        
                            
            
                                    
            
            
                | 73 |  |  |         array $decryption = array() | 
            
                                                                        
                            
            
                                    
            
            
                | 74 |  |  |     ) { | 
            
                                                                        
                            
            
                                    
            
            
                | 75 | 11 |  |         parent::__construct($logger, $encryption, $decryption); | 
            
                                                                        
                            
            
                                    
            
            
                | 76 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 77 |  |  |         // Set our own properties | 
            
                                                                        
                            
            
                                    
            
            
                | 78 | 11 |  |         $this->handle = $handle; | 
            
                                                                        
                            
            
                                    
            
            
                | 79 | 11 |  |         $this->tableName = $tableName; | 
            
                                                                        
                            
            
                                    
            
            
                | 80 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 82 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 83 |  |  |      * @see Tiqr_UserSecretStorage_Interface::userExists() | 
            
                                                                        
                            
            
                                    
            
            
                | 84 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 85 |  |  |      * Note: duplicate of Tiqr_UserStorage_Pdo::userExists() | 
            
                                                                        
                            
            
                                    
            
            
                | 86 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 | 5 |  |     public function userExists(string $userId): bool | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |         try { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 5 |  |             $sth = $this->handle->prepare('SELECT userid FROM ' . $this->tableName . ' WHERE userid = ?'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 | 5 |  |             $sth->execute(array($userId)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 5 |  |             return (false !== $sth->fetchColumn()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         catch (Exception $e) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |             $this->logger->error('PDO error checking user exists', array('exception'=>$e, 'userId'=>$userId)); | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 96 |  |  |             throw ReadWriteException::fromOriginalException($e); | 
            
                                                                        
                            
            
                                    
            
            
                | 97 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 99 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 100 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 101 |  |  |      * Get the user's secret | 
            
                                                                        
                            
            
                                    
            
            
                | 102 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 103 |  |  |      * @param String $userId | 
            
                                                                        
                            
            
                                    
            
            
                | 104 |  |  |      * @return string | 
            
                                                                        
                            
            
                                    
            
            
                | 105 |  |  |      * @throws Exception | 
            
                                                                        
                            
            
                                    
            
            
                | 106 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 107 | 3 |  |     protected function getUserSecret(string $userId): string | 
            
                                                                        
                            
            
                                    
            
            
                | 108 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 109 |  |  |         try { | 
            
                                                                        
                            
            
                                    
            
            
                | 110 | 3 |  |             $sth = $this->handle->prepare('SELECT secret FROM ' . $this->tableName . ' WHERE userid = ?'); | 
            
                                                                        
                            
            
                                    
            
            
                | 111 | 3 |  |             $sth->execute(array($userId)); | 
            
                                                                        
                            
            
                                    
            
            
                | 112 | 3 |  |             $res=$sth->fetchColumn(); | 
            
                                                                        
                            
            
                                    
            
            
                | 113 | 3 |  |             if ($res === false) { | 
            
                                                                        
                            
            
                                    
            
            
                | 114 |  |  |                 // No result | 
            
                                                                        
                            
            
                                    
            
            
                | 115 |  |  |                 $this->logger->error(sprintf('No result getting secret for user "%s"', $userId)); | 
            
                                                                        
                            
            
                                    
            
            
                | 116 | 3 |  |                 throw new RuntimeException('User not found'); | 
            
                                                                        
                            
            
                                    
            
            
                | 117 |  |  |             } | 
            
                                                                        
                            
            
                                    
            
            
                | 118 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 119 |  |  |         catch (Exception $e) { | 
            
                                                                        
                            
            
                                    
            
            
                | 120 |  |  |             $this->logger->error('PDO error getting user', array('exception' => $e, 'userId' => $userId)); | 
            
                                                                        
                            
            
                                    
            
            
                | 121 |  |  |             throw ReadWriteException::fromOriginalException($e); | 
            
                                                                        
                            
            
                                    
            
            
                | 122 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 123 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 124 | 3 |  |         if (!is_string($res)) { | 
            
                                                                        
                            
            
                                    
            
            
                | 125 |  |  |             $this->logger->error(sprintf('No secret found for user "%s"', $userId)); | 
            
                                                                        
                            
            
                                    
            
            
                | 126 |  |  |             throw new RuntimeException('Secret not found'); | 
            
                                                                        
                            
            
                                    
            
            
                | 127 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 128 | 3 |  |         return $res; | 
            
                                                                        
                            
            
                                    
            
            
                | 129 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 130 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 131 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 132 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 133 |  |  |      * @throws Exception | 
            
                                                                        
                            
            
                                    
            
            
                | 134 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 135 | 5 |  |     protected function setUserSecret(string $userId, string $secret): void | 
            
                                                                        
                            
            
                                    
            
            
                | 136 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 137 |  |  |         // UserSecretStorage can be used in a separate table. In this case the table has its own userid column | 
            
                                                                        
                            
            
                                    
            
            
                | 138 |  |  |         // This means that when a user has been created using in the UserStorage, it does not exists in the | 
            
                                                                        
                            
            
                                    
            
            
                | 139 |  |  |         // UserSecretStorage so userExists will be false and we need to use an INSERT query. | 
            
                                                                        
                            
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 141 |  |  |         // It is also possible to use one table for both the UserStorage and the UserSecretStorage, in that case the | 
            
                                                                        
                            
            
                                    
            
            
                | 142 |  |  |         // userid column is shared between the UserStorage and UserSecretStorage and the user must first have been created | 
            
                                                                        
                            
            
                                    
            
            
                | 143 |  |  |         // in the UserStorage because: | 
            
                                                                        
                            
            
                                    
            
            
                | 144 |  |  |         // - UserStorage_Pdo::create() no longer supports overwriting an existing user | 
            
                                                                        
                            
            
                                    
            
            
                | 145 |  |  |         // - The INSERT will fail when displayname has a NOT NULL constraint | 
            
                                                                        
                            
            
                                    
            
            
                | 146 |  |  |         try { | 
            
                                                                        
                            
            
                                    
            
            
                | 147 | 5 |  |             if ($this->userExists($userId)) { | 
            
                                                                        
                            
            
                                    
            
            
                | 148 | 2 |  |                 $sth = $this->handle->prepare('UPDATE ' . $this->tableName . ' SET secret = ? WHERE userid = ?'); | 
            
                                                                        
                            
            
                                    
            
            
                | 149 |  |  |             } else { | 
            
                                                                        
                            
            
                                    
            
            
                | 150 | 3 |  |                 $sth = $this->handle->prepare('INSERT INTO ' . $this->tableName . ' (secret,userid) VALUES (?,?)'); | 
            
                                                                        
                            
            
                                    
            
            
                | 151 |  |  |             } | 
            
                                                                        
                            
            
                                    
            
            
                | 152 | 4 |  |             $sth->execute(array($secret, $userId)); | 
            
                                                                        
                            
            
                                    
            
            
                | 153 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 154 | 2 |  |         catch (Exception $e) { | 
            
                                                                        
                            
            
                                    
            
            
                | 155 | 2 |  |             $this->logger->error( | 
            
                                                                        
                            
            
                                    
            
            
                | 156 | 2 |  |                 sprintf('Unable to persist user secret for user "%s" in user secret storage (PDO)', $userId), | 
            
                                                                        
                            
            
                                    
            
            
                | 157 | 2 |  |                 array('exception'=>$e) | 
            
                                                                        
                            
            
                                    
            
            
                | 158 | 2 |  |             ); | 
            
                                                                        
                            
            
                                    
            
            
                | 159 | 2 |  |             throw ReadWriteException::fromOriginalException($e); | 
            
                                                                        
                            
            
                                    
            
            
                | 160 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 161 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 162 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 163 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 164 |  |  |      * @see Tiqr_UserSecretStorage_Interface::healthCheck() | 
            
                                                                        
                            
            
                                    
            
            
                | 165 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 | 2 |  |     public function healthCheck(string &$statusMessage = ''): bool | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |         // Check whether the table exists by reading a random row | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |         try { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 | 2 |  |             $sth = $this->handle->prepare('SELECT secret FROM '.$this->tableName.' LIMIT 1'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 | 1 |  |             $sth->execute(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 | 1 |  |         catch (Exception $e) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 | 1 |  |             $statusMessage = "UserSecretStorage_PDO error: " . $e->getMessage(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 | 1 |  |             return false; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 178 | 1 |  |         return true; | 
            
                                                                        
                                                                
            
                                    
            
            
                | 179 |  |  |     } | 
            
                                                                        
                                                                
            
                                    
            
            
                | 180 |  |  | } | 
            
                                                                        
                                                                
            
                                    
            
            
                | 181 |  |  |  |