Fixes #6444, #6419 oauth2 redirect, imports (#6445)
[openemr.git] / src / Common / Auth / OpenIDConnect / Repositories / ClientRepository.php
blobd004de7683857ec6db20eb37beeb595363c4aa08
1 <?php
3 /**
4 * Authorization Server Member
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @copyright Copyright (c) 2020 Jerry Padgett <sjpadgett@gmail.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 namespace OpenEMR\Common\Auth\OpenIDConnect\Repositories;
15 use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
16 use OpenEMR\Common\Auth\OpenIDConnect\Entities\ClientEntity;
17 use OpenEMR\Common\Crypto\CryptoGen;
18 use OpenEMR\Common\Logging\SystemLogger;
19 use Psr\Log\LoggerInterface;
21 class ClientRepository implements ClientRepositoryInterface
23 /**
24 * @var LoggerInterface
26 private $logger;
28 public function __construct()
30 $this->logger = new SystemLogger();
33 /**
34 * @return ClientEntity[]
36 public function listClientEntities(): array
38 $clients = sqlStatementNoLog("Select * From oauth_clients ORDER BY is_enabled DESC, register_date DESC");
39 $list = [];
40 if (!empty($clients)) {
41 while ($client = $clients->FetchRow()) {
42 $list[] = $this->hydrateClientEntityFromArray($client);
45 return $list;
48 public function getClientEntity($clientIdentifier)
50 $clients = sqlQueryNoLog("Select * From oauth_clients Where client_id=?", array($clientIdentifier));
52 // Check if client is registered
53 if ($clients === false) {
54 $this->logger->error(
55 "ClientRepository->getClientEntity() no client found for identifier ",
56 ["client" => $clientIdentifier]
58 return false;
61 $this->logger->debug(
62 "ClientRepository->getClientEntity() client found",
64 "client" => [
65 "client_name" => $clients['client_name'],
66 "redirect_uri" => $clients['redirect_uri'],
67 "is_confidential" => $clients['is_confidential']
71 return $this->hydrateClientEntityFromArray($clients);
74 public function validateClient($clientIdentifier, $clientSecret, $grantType): bool
76 $this->logger->debug(
77 "ClientRepository->validateClient() checking client validation",
78 ["client" => $clientIdentifier, "grantType" => $grantType]
80 if ($grantType == 'authorization_code') {
81 $client = sqlQueryNoLog("SELECT `client_secret`, `is_confidential` FROM `oauth_clients` WHERE `client_id` = ?", [$clientIdentifier]);
83 // Check if client is registered
84 if ($client === false) {
85 $this->logger->error(
86 "ClientRepository->validateClient() no client found for identifier ",
87 ["client" => $clientIdentifier]
89 return false;
92 // Validate client if is_confidential
93 if (!empty($clientSecret) && !empty($client['is_confidential'])) {
94 $secret = (new CryptoGen())->decryptStandard($client['client_secret']);
95 if (empty($secret)) {
96 return false;
98 $secretMatches = hash_equals($clientSecret, $secret);
99 if (!$secretMatches) {
100 $this->logger->error(
101 "ClientRepository->validateClient() Confidential client sent invalid client secret. Validation failed",
102 ["client" => $clientIdentifier, "grantType" => $grantType]
105 return $secretMatches;
108 return true;
109 } else {
110 // password and refresh grant
111 return true;
116 * Set a client in the database to be enabled if $isEnabled is true or disabled if $isEnabled is false.
117 * @param ClientEntity $client
118 * @param $isEnabled
119 * @return bool True if it succeeded
120 * @throws \RuntimeException If there is a database error in saving.
122 public function saveIsEnabled(ClientEntity $client, $isEnabled)
124 // TODO: adunsulag do we want to eventually just have a save() method.. it would be very handy but not sure
125 // we want any oauth2 values being overwritten.
126 $isEnabledSaveValue = $isEnabled === true ? 1 : 0;
127 $clientId = $client->getIdentifier();
128 $params = [$isEnabledSaveValue, $clientId];
129 $res = sqlStatement("UPDATE oauth_clients SET is_enabled=? WHERE client_id = ?", $params);
130 if ($res === false) {
131 // TODO: adunsulag is there a better exception to throw here in OpenEMR than runtime?
132 throw new \RuntimeException("Failed to save oauth_clients is_enabled flag. Check logs for sql error");
134 return true;
138 * @param $client_record
139 * @return ClientEntity
141 private function hydrateClientEntityFromArray($client_record): ClientEntity
143 // note redirect_uris in the database is actually named redirect_uri
144 $pipedValues = array('contacts', 'redirect_uri', 'request_uri', 'post_logout_redirect_uris', 'grant_types', 'response_types', 'default_acr_values');
145 foreach ($pipedValues as $value) {
146 if (!empty($client_record[$value])) {
147 $client_record[$value] = explode('|', $client_record[$value]);
150 $client = new ClientEntity();
151 $client->setIdentifier($client_record['client_id']);
152 $client->setName($client_record['client_name']);
153 $client->setRedirectUri($client_record['redirect_uri']);
154 $client->setIsConfidential($client_record['is_confidential']);
155 $client->setScopes($client_record['scope']);
156 $client->setClientRole($client_record['client_role']);
157 // launch uri is the same as the initiate_login_uri SMART uses launchUri
158 // so we will refer to it that way.
159 $client->setLaunchUri($client_record['initiate_login_uri']);
160 $client->setIsEnabled($client_record['is_enabled'] == "1");
161 $client->setJwks($client_record['jwks']);
162 $client->setJwksUri($client_record['jwks_uri']);
163 $client->setLogoutRedirectUris($client_record['logout_redirect_uris']);
164 $client->setContacts($client_record['contacts']);
165 $client->setRegistrationDate($client_record['register_date']);
166 return $client;