Skip to content

Commit e99b15a

Browse files
committed
Merge #15 Telekom bearer token: Additional secret V31
2 parents 92014cf + d841f1b commit e99b15a

File tree

8 files changed

+577
-5
lines changed

8 files changed

+577
-5
lines changed

lib/Command/UpsertProvider.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ protected function configure() {
150150
->addOption('clientsecret', 's', InputOption::VALUE_REQUIRED, 'OpenID client secret')
151151
->addOption('discoveryuri', 'd', InputOption::VALUE_REQUIRED, 'OpenID discovery endpoint uri')
152152
->addOption('endsessionendpointuri', 'e', InputOption::VALUE_OPTIONAL, 'OpenID end session endpoint uri')
153+
->addOption('bearersecret', 'bs', InputOption::VALUE_OPTIONAL, 'Telekom bearer token requires a different client secret for bearer tokens')
153154
->addOption('scope', 'o', InputOption::VALUE_OPTIONAL, 'OpenID requested value scopes, if not set defaults to "openid email profile"');
154155
foreach (self::EXTRA_OPTIONS as $name => $option) {
155156
$this->addOption($name, $option['shortcut'], $option['mode'], $option['description']);
@@ -174,10 +175,17 @@ protected function execute(InputInterface $input, OutputInterface $output) {
174175
return $this->listProviders($input, $output);
175176
}
176177

178+
// bearersecret is usually base64 encoded, but SAM delivers it non-encoded by default
179+
// so always encode/decode for this field
180+
$bearersecret = $input->getOption('bearersecret');
181+
if ($bearersecret !== null) {
182+
$bearersecret = $this->crypto->encrypt(\Base64Url\Base64Url::encode($bearersecret));
183+
}
184+
177185
// check if any option for updating is provided
178186
$updateOptions = array_filter($input->getOptions(), static function ($value, $option) {
179187
return in_array($option, [
180-
'identifier', 'clientid', 'clientsecret', 'discoveryuri', 'scope',
188+
'identifier', 'clientid', 'clientsecret', 'discoveryuri', 'scope', 'bearersecret',
181189
...array_keys(self::EXTRA_OPTIONS),
182190
]) && $value !== null;
183191
}, ARRAY_FILTER_USE_BOTH);
@@ -217,7 +225,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
217225
$scope = $scope ?? 'openid email profile';
218226
}
219227
try {
220-
$provider = $this->providerMapper->createOrUpdateProvider($identifier, $clientid, $clientsecret, $discoveryuri, $scope, $endsessionendpointuri);
228+
$provider = $this->providerMapper->createOrUpdateProvider($identifier, $clientid, $clientsecret, $discoveryuri, $scope, $endsessionendpointuri, $bearersecret);
221229
// invalidate JWKS cache (even if it was just created)
222230
$this->providerService->setSetting($provider->getId(), ProviderService::SETTING_JWKS_CACHE, '');
223231
$this->providerService->setSetting($provider->getId(), ProviderService::SETTING_JWKS_CACHE_TIMESTAMP, '');

lib/Controller/SettingsController.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function isDiscoveryEndpointValid($url) {
7676
/**
7777
* @PasswordConfirmationRequired
7878
*/
79-
public function createProvider(string $identifier, string $clientId, string $clientSecret, string $discoveryEndpoint,
79+
public function createProvider(string $identifier, string $clientId, string $clientSecret, string $discoveryEndpoint, string $bearerSecret,
8080
array $settings = [], string $scope = 'openid email profile', ?string $endSessionEndpoint = null): JSONResponse {
8181
if ($this->providerService->getProviderByIdentifier($identifier) !== null) {
8282
return new JSONResponse(['message' => 'Provider with the given identifier already exists'], Http::STATUS_CONFLICT);
@@ -99,6 +99,8 @@ public function createProvider(string $identifier, string $clientId, string $cli
9999
$provider->setDiscoveryEndpoint($discoveryEndpoint);
100100
$provider->setEndSessionEndpoint($endSessionEndpoint ?: null);
101101
$provider->setScope($scope);
102+
$encryptedBearerSecret = $this->crypto->encrypt(\Base64Url\Base64Url::encode($bearerSecret));
103+
$provider->setBearerSecret($encryptedBearerSecret);
102104
$provider = $this->providerMapper->insert($provider);
103105

104106
$providerSettings = $this->providerService->setSettings($provider->getId(), $settings);
@@ -109,7 +111,7 @@ public function createProvider(string $identifier, string $clientId, string $cli
109111
/**
110112
* @PasswordConfirmationRequired
111113
*/
112-
public function updateProvider(int $providerId, string $identifier, string $clientId, string $discoveryEndpoint, ?string $clientSecret = null,
114+
public function updateProvider(int $providerId, string $identifier, string $clientId, string $discoveryEndpoint, ?string $clientSecret = null, ?string $bearerSecret = null,
113115
array $settings = [], string $scope = 'openid email profile', ?string $endSessionEndpoint = null): JSONResponse {
114116
$provider = $this->providerMapper->getProvider($providerId);
115117

lib/Db/Provider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
* @method void setClientId(string $clientId)
1818
* @method string getClientSecret()
1919
* @method void setClientSecret(string $clientSecret)
20+
* @method string getBearerSecret()
21+
* @method void setBearerSecret(string $bearerSecret)
2022
* @method string getDiscoveryEndpoint()
2123
* @method void setDiscoveryEndpoint(string $discoveryEndpoint)
2224
* @method string getEndSessionEndpoint()
2325
* @method void setEndSessionEndpoint(string $endSessionEndpoint)
26+
* @method string getScope()
2427
* @method void setScope(string $scope)
2528
*/
2629
class Provider extends Entity implements \JsonSerializable {
@@ -34,6 +37,9 @@ class Provider extends Entity implements \JsonSerializable {
3437
/** @var string */
3538
protected $clientSecret;
3639

40+
/** @var string */
41+
protected $bearerSecret;
42+
3743
/** @var string */
3844
protected $discoveryEndpoint;
3945

lib/Db/ProviderMapper.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public function getProviders() {
8080
* @param string $identifier
8181
* @param string|null $clientid
8282
* @param string|null $clientsecret
83+
* @param string|null $bearersecret
8384
* @param string|null $discoveryuri
8485
* @param string $scope
8586
* @param string|null $endsessionendpointuri
@@ -90,7 +91,7 @@ public function getProviders() {
9091
*/
9192
public function createOrUpdateProvider(string $identifier, ?string $clientid = null,
9293
?string $clientsecret = null, ?string $discoveryuri = null, string $scope = 'openid email profile',
93-
?string $endsessionendpointuri = null) {
94+
?string $endsessionendpointuri = null, ?string $bearersecret = null) {
9495
try {
9596
$provider = $this->findProviderByIdentifier($identifier);
9697
} catch (DoesNotExistException $eNotExist) {
@@ -105,6 +106,7 @@ public function createOrUpdateProvider(string $identifier, ?string $clientid = n
105106
$provider->setIdentifier($identifier);
106107
$provider->setClientId($clientid);
107108
$provider->setClientSecret($clientsecret);
109+
$provider->setBearerSecret($bearersecret ?? '');
108110
$provider->setDiscoveryEndpoint($discoveryuri);
109111
$provider->setEndSessionEndpoint($endsessionendpointuri);
110112
$provider->setScope($scope);
@@ -116,6 +118,9 @@ public function createOrUpdateProvider(string $identifier, ?string $clientid = n
116118
if ($clientsecret !== null) {
117119
$provider->setClientSecret($clientsecret);
118120
}
121+
if ($bearersecret !== null) {
122+
$provider->setBearerSecret($bearersecret);
123+
}
119124
if ($discoveryuri !== null) {
120125
$provider->setDiscoveryEndpoint($discoveryuri);
121126
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OCA\UserOIDC\Migration;
6+
7+
use Closure;
8+
use OCP\DB\ISchemaWrapper;
9+
use OCP\Migration\IOutput;
10+
use OCP\Migration\SimpleMigrationStep;
11+
12+
class Version00008Date20211114183344 extends SimpleMigrationStep {
13+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
14+
/** @var ISchemaWrapper $schema */
15+
$schema = $schemaClosure();
16+
17+
$table = $schema->getTable('user_oidc_providers');
18+
$table->addColumn('bearer_secret', 'string', [
19+
'notnull' => true,
20+
'length' => 64,
21+
]);
22+
23+
return $schema;
24+
}
25+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright 2023, Julien Veyssier <julien-nc@posteo.net>
7+
*
8+
* @author B. Rederlechner <bernd.rederlechner@t-systems.com>
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+
namespace OCA\UserOIDC\Migration;
27+
28+
use Closure;
29+
use OCP\DB\ISchemaWrapper;
30+
use OCP\DB\QueryBuilder\IQueryBuilder;
31+
use OCP\IDBConnection;
32+
use OCP\Migration\IOutput;
33+
use OCP\Migration\SimpleMigrationStep;
34+
use OCP\Security\ICrypto;
35+
36+
class Version010304Date20230902125945 extends SimpleMigrationStep {
37+
38+
/**
39+
* @var IDBConnection
40+
*/
41+
private $connection;
42+
/**
43+
* @var ICrypto
44+
*/
45+
private $crypto;
46+
47+
public function __construct(
48+
IDBConnection $connection,
49+
ICrypto $crypto,
50+
) {
51+
$this->connection = $connection;
52+
$this->crypto = $crypto;
53+
}
54+
55+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
56+
/** @var ISchemaWrapper $schema */
57+
$schema = $schemaClosure();
58+
$tableName = 'user_oidc_providers';
59+
60+
if ($schema->hasTable($tableName)) {
61+
$table = $schema->getTable($tableName);
62+
if ($table->hasColumn('bearer_secret')) {
63+
$column = $table->getColumn('bearer_secret');
64+
$column->setLength(512);
65+
return $schema;
66+
}
67+
}
68+
69+
return null;
70+
}
71+
72+
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
73+
$tableName = 'user_oidc_providers';
74+
75+
// update secrets in user_oidc_providers and user_oidc_id4me
76+
$qbUpdate = $this->connection->getQueryBuilder();
77+
$qbUpdate->update($tableName)
78+
->set('bearer_secret', $qbUpdate->createParameter('updateSecret'))
79+
->where(
80+
$qbUpdate->expr()->eq('id', $qbUpdate->createParameter('updateId'))
81+
);
82+
83+
$qbSelect = $this->connection->getQueryBuilder();
84+
$qbSelect->select('id', 'bearer_secret')
85+
->from($tableName);
86+
$req = $qbSelect->executeQuery();
87+
while ($row = $req->fetch()) {
88+
$id = $row['id'];
89+
$secret = $row['bearer_secret'];
90+
$encryptedSecret = $this->crypto->encrypt($secret);
91+
$qbUpdate->setParameter('updateSecret', $encryptedSecret, IQueryBuilder::PARAM_STR);
92+
$qbUpdate->setParameter('updateId', $id, IQueryBuilder::PARAM_INT);
93+
$qbUpdate->executeStatement();
94+
}
95+
$req->closeCursor();
96+
}
97+
}

src/components/SettingsForm.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@
3232
:required="!update"
3333
autocomplete="off">
3434
</p>
35+
<p>
36+
<label for="oidc-bearer-secret">{{ t('user_oidc', 'Bearer shared secret') }}</label>
37+
<input id="oidc-bearer-secret"
38+
v-model="localProvider.bearerSecret"
39+
:placeholder="update ? t('user_oidc', 'Leave empty to keep existing') : null"
40+
type="text"
41+
:required="!update"
42+
autocomplete="off">
43+
</p>
3544
<p class="settings-hint warning-hint">
3645
<AlertOutlineIcon :size="20" class="icon" />
3746
{{ t('user_oidc', 'Warning, if the protocol of the URLs in the discovery content is HTTP, the ID token will be delivered through an insecure connection.') }}

0 commit comments

Comments
 (0)