Skip to content

Commit cecbc43

Browse files
committed
Merge #6 Telekom bearer token: additional secret
2 parents 31ffad8 + e71c92d commit cecbc43

File tree

8 files changed

+580
-6
lines changed

8 files changed

+580
-6
lines changed

lib/Command/UpsertProvider.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ protected function configure() {
7373
->addOption('mapping-quota', null, InputOption::VALUE_OPTIONAL, 'Attribute mapping of the quota')
7474
->addOption('mapping-uid', null, InputOption::VALUE_OPTIONAL, 'Attribute mapping of the user id')
7575
->addOption('extra-claims', null, InputOption::VALUE_OPTIONAL, 'Extra claims to request when getting tokens')
76-
76+
->addOption('bearersecret', 'bs', InputOption::VALUE_OPTIONAL, 'Telekom bearer token requires a different client secret for bearer tokens')
7777
->addOption(
7878
'output',
7979
null,
@@ -100,11 +100,18 @@ protected function execute(InputInterface $input, OutputInterface $output) {
100100
return $this->listProviders($input, $output);
101101
}
102102

103+
// bearersecret is usually base64 encoded, but SAM delivers it non-encoded
104+
// by default; so always encode/decode for this field
105+
$bearersecret = $input->getOption('bearersecret');
106+
if ($bearersecret !== null) {
107+
$bearersecret = $this->crypto->encrypt(\Base64Url\Base64Url::encode($bearersecret));
108+
}
109+
103110
// check if any option for updating is provided
104111
$updateOptions = array_filter($input->getOptions(), static function ($value, $option) {
105112
return in_array($option, [
106113
'identifier', 'clientid', 'clientsecret', 'discoveryuri',
107-
'scope', 'unique-uid', 'check-bearer',
114+
'scope', 'unique-uid', 'check-bearer', 'bearersecret',
108115
'mapping-uid', 'mapping-display-name', 'mapping-email', 'mapping-quota',
109116
'extra-claims'
110117
]) && $value !== null;
@@ -146,7 +153,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
146153
$scope = $scope ?? 'openid email profile';
147154
}
148155
try {
149-
$provider = $this->providerMapper->createOrUpdateProvider($identifier, $clientid, $clientsecret, $discoveryuri, $scope);
156+
$provider = $this->providerMapper->createOrUpdateProvider($identifier, $clientid, $clientsecret, $discoveryuri, $scope, $bearersecret);
150157
// invalidate JWKS cache (even if it was just created)
151158
$this->providerService->setSetting($provider->getId(), ProviderService::SETTING_JWKS_CACHE, '');
152159
$this->providerService->setSetting($provider->getId(), ProviderService::SETTING_JWKS_CACHE_TIMESTAMP, '');

lib/Controller/SettingsController.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function __construct(
6464
}
6565

6666
public function createProvider(string $identifier, string $clientId, string $clientSecret, string $discoveryEndpoint,
67-
array $settings = [], string $scope = 'openid email profile'): JSONResponse {
67+
string $bearerSecret, array $settings = [], string $scope = 'openid email profile'): JSONResponse {
6868
if ($this->providerService->getProviderByIdentifier($identifier) !== null) {
6969
return new JSONResponse(['message' => 'Provider with the given identifier already exists'], Http::STATUS_CONFLICT);
7070
}
@@ -76,6 +76,8 @@ public function createProvider(string $identifier, string $clientId, string $cli
7676
$provider->setClientSecret($encryptedClientSecret);
7777
$provider->setDiscoveryEndpoint($discoveryEndpoint);
7878
$provider->setScope($scope);
79+
$encryptedBearerSecret = $this->crypto->encrypt(\Base64Url\Base64Url::encode($bearerSecret));
80+
$provider->setBearerSecret($encryptedBearerSecret);
7981
$provider = $this->providerMapper->insert($provider);
8082

8183
$providerSettings = $this->providerService->setSettings($provider->getId(), $settings);
@@ -84,7 +86,7 @@ public function createProvider(string $identifier, string $clientId, string $cli
8486
}
8587

8688
public function updateProvider(int $providerId, string $identifier, string $clientId, string $discoveryEndpoint, string $clientSecret = null,
87-
array $settings = [], string $scope = 'openid email profile'): JSONResponse {
89+
string $bearerSecret = null, array $settings = [], string $scope = 'openid email profile'): JSONResponse {
8890
$provider = $this->providerMapper->getProvider($providerId);
8991

9092
if ($this->providerService->getProviderByIdentifier($identifier) === null) {
@@ -97,6 +99,9 @@ public function updateProvider(int $providerId, string $identifier, string $clie
9799
$encryptedClientSecret = $this->crypto->encrypt($clientSecret);
98100
$provider->setClientSecret($encryptedClientSecret);
99101
}
102+
if ($bearerSecret) {
103+
$provider->setBearerSecret(\Base64Url\Base64Url::encode($bearerSecret));
104+
}
100105
$provider->setDiscoveryEndpoint($discoveryEndpoint);
101106
$provider->setScope($scope);
102107
$provider = $this->providerMapper->update($provider);

lib/Db/Provider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@
3434
* @method void setClientId(string $clientId)
3535
* @method string getClientSecret()
3636
* @method void setClientSecret(string $clientSecret)
37+
* @method string getBearerSecret()
38+
* @method void setBearerSecret(string $bearerSecret)
3739
* @method string getDiscoveryEndpoint()
3840
* @method void setDiscoveryEndpoint(string $discoveryEndpoint)
41+
* @method string getScope()
3942
* @method void setScope(string $scope)
4043
*/
4144
class Provider extends Entity implements \JsonSerializable {
@@ -55,6 +58,9 @@ class Provider extends Entity implements \JsonSerializable {
5558
/** @var string */
5659
protected $scope;
5760

61+
/** @var string */
62+
protected $bearerSecret;
63+
5864
/**
5965
* @return string
6066
*/

lib/Db/ProviderMapper.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ public function getProviders() {
9393
* @param string|null $clientsecret
9494
* @param string|null $discoveryuri
9595
* @param string scope
96+
* @param string|null $bearersecret
9697
* @throws \OCP\AppFramework\Db\DoesNotExistException
9798
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
9899
*/
99100
public function createOrUpdateProvider(string $identifier, string $clientid = null,
100101
string $clientsecret = null, string $discoveryuri = null,
101-
string $scope = 'openid email profile') {
102+
string $scope = 'openid email profile', string $bearersecret = null) {
102103
try {
103104
$provider = $this->findProviderByIdentifier($identifier);
104105
} catch (DoesNotExistException $eNotExist) {
@@ -115,6 +116,7 @@ public function createOrUpdateProvider(string $identifier, string $clientid = nu
115116
$provider->setClientSecret($clientsecret);
116117
$provider->setDiscoveryEndpoint($discoveryuri);
117118
$provider->setScope($scope);
119+
$provider->setBearerSecret($bearersecret ?? '');
118120
return $this->insert($provider);
119121
} else {
120122
if ($clientid !== null) {
@@ -126,6 +128,9 @@ public function createOrUpdateProvider(string $identifier, string $clientid = nu
126128
if ($discoveryuri !== null) {
127129
$provider->setDiscoveryEndpoint($discoveryuri);
128130
}
131+
if ($bearersecret !== null) {
132+
$provider->setBearerSecret($bearersecret);
133+
}
129134
$provider->setScope($scope);
130135
return $this->update($provider);
131136
}
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
@@ -46,6 +46,15 @@
4646
:required="!update"
4747
autocomplete="off">
4848
</p>
49+
<p>
50+
<label for="oidc-bearer-secret">{{ t('user_oidc', 'Bearer shared secret') }}</label>
51+
<input id="oidc-bearer-secret"
52+
v-model="localProvider.bearerSecret"
53+
:placeholder="update ? t('user_oidc', 'Leave empty to keep existing') : null"
54+
type="text"
55+
:required="!update"
56+
autocomplete="off">
57+
</p>
4958
<p class="settings-hint">
5059
<AlertOutlineIcon :size="20" class="icon" />
5160
{{ 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)