Skip to content
This repository was archived by the owner on Sep 19, 2022. It is now read-only.

Commit 091289f

Browse files
committed
fix: use only file configuration for challenges
Use only file configuration for challanges BREAKING CHANGE: Rewrite challenge manager + Changes in configuration
1 parent a6ce604 commit 091289f

File tree

5 files changed

+174
-195
lines changed

5 files changed

+174
-195
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
$config = array(
4+
/**
5+
* Path to public key
6+
*/
7+
'pubKey' => 'Path_to_public_key',
8+
9+
/**
10+
* Path to private key
11+
*/
12+
'privKey' => 'Path_to_private_key',
13+
14+
/**
15+
* Hash algorithm
16+
*/
17+
'hashAlg' => 'sha256',
18+
19+
/**
20+
* Signature algorith
21+
*/
22+
'sigAlg' => 'RS512',
23+
24+
/**
25+
* Challenge length
26+
*/
27+
'challengeLength' => 64,
28+
);

lib/Auth/Process/UpdateUserExtSource.php

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,8 @@
22

33
namespace SimpleSAML\Module\perun\Auth\Process;
44

5-
use Jose\Component\KeyManagement\JWKFactory;
6-
use Jose\Component\Core\AlgorithmManager;
7-
use Jose\Component\Signature\JWSBuilder;
8-
use Jose\Component\Signature\Serializer\CompactSerializer;
9-
use Jose\Component\Signature\Algorithm\RS512;
105
use SimpleSAML\Auth\ProcessingFilter;
116
use SimpleSAML\Error\Exception;
12-
use SimpleSAML\Logger;
137
use SimpleSAML\Module;
148
use SimpleSAML\Module\perun\ChallengeManager;
159
use SimpleSAML\Module\perun\UpdateUESThread;
@@ -26,8 +20,6 @@ class UpdateUserExtSource extends ProcessingFilter
2620
{
2721
private $attrMap;
2822
private $attrsToConversion;
29-
private $pathToKey;
30-
private $signatureAlg;
3123

3224
const SCRIPT_NAME = 'updateUes';
3325

@@ -43,83 +35,27 @@ public function __construct($config, $reserved)
4335
);
4436
}
4537

46-
if (!isset($config['pathToKey'])) {
47-
throw new Exception(
48-
'perun:UpdateUserExtSource: missing mandatory configuration option \'pathToKey\'.'
49-
);
50-
}
51-
5238
if (isset($config['arrayToStringConversion'])) {
5339
$this->attrsToConversion = (array)$config['arrayToStringConversion'];
5440
} else {
5541
$this->attrsToConversion = [];
5642
}
5743

58-
if (isset($config['signatureAlg'])) {
59-
$this->signatureAlg = (array)$config['signatureAlg'];
60-
} else {
61-
$this->signatureAlg = 'RS512';
62-
}
63-
6444
$this->attrMap = (array)$config['attrMap'];
65-
$this->pathToKey = $config['pathToKey'];
6645
}
6746

6847
public function process(&$request)
6948
{
7049
$id = uniqid("", true);
7150

72-
$dataChallenge = [
73-
'id' => $id,
74-
'scriptName' => self::SCRIPT_NAME
75-
];
76-
77-
$json = json_encode($dataChallenge);
78-
79-
$curlChallenge = curl_init();
80-
curl_setopt($curlChallenge, CURLOPT_POSTFIELDS, $json);
81-
curl_setopt($curlChallenge, CURLOPT_URL, Module::getModuleURL('perun/getChallenge.php'));
82-
curl_setopt($curlChallenge, CURLOPT_RETURNTRANSFER, true);
83-
84-
$challenge = curl_exec($curlChallenge);
85-
86-
if (empty($challenge)) {
87-
Logger::error('Retrieving the challenge was not successful.');
88-
return;
89-
}
90-
91-
$jwk = JWKFactory::createFromKeyFile($this->pathToKey);
92-
$algorithmManager = new AlgorithmManager(
93-
[
94-
ChallengeManager::getAlgorithm('Signature\\Algorithm', $this->signatureAlg)
95-
]
96-
);
97-
$jwsBuilder = new JWSBuilder($algorithmManager);
98-
51+
$challengeManager = new ChallengeManager();
9952
$data = [
10053
'attributes' => $request['Attributes'],
10154
'attrMap' => $this->attrMap,
10255
'attrsToConversion' => $this->attrsToConversion,
10356
'perunUserId' => $request['perun']['user']->getId()
10457
];
105-
106-
$payload = json_encode([
107-
'iat' => time(),
108-
'nbf' => time(),
109-
'exp' => time() + 300,
110-
'challenge' => $challenge,
111-
'id' => $id,
112-
'data' => $data
113-
]);
114-
115-
$jws = $jwsBuilder
116-
->create()
117-
->withPayload($payload)
118-
->addSignature($jwk, ['alg' => $this->signatureAlg])
119-
->build();
120-
121-
$serializer = new CompactSerializer();
122-
$token = $serializer->serialize($jws, 0);
58+
$token = $challengeManager->generateToken($id, self::SCRIPT_NAME, $data);
12359

12460
$cmd = 'curl -X POST -H "Content-Type: application/json" -d ' . escapeshellarg($token) . ' ' .
12561
escapeshellarg(Module::getModuleURL('perun/updateUes.php')) . ' > /dev/null &';

lib/ChallengeManager.php

Lines changed: 141 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,166 @@
22

33
namespace SimpleSAML\Module\perun;
44

5+
use SimpleSAML\Configuration;
56
use SimpleSAML\Logger;
67
use SimpleSAML\Module\perun\databaseCommand\ChallengesDbCmd;
8+
use Jose\Component\KeyManagement\JWKFactory;
9+
use Jose\Component\Core\AlgorithmManager;
10+
use Jose\Component\Signature\JWSBuilder;
11+
use Jose\Component\Signature\Serializer\CompactSerializer;
12+
use Jose\Component\Checker\AlgorithmChecker;
13+
use Jose\Component\Checker\ClaimCheckerManager;
14+
use Jose\Component\Checker\HeaderCheckerManager;
15+
use Jose\Component\Signature\JWSTokenSupport;
16+
use Jose\Component\Signature\JWSVerifier;
17+
use Jose\Component\Signature\Serializer\JWSSerializerManager;
18+
use Jose\Component\Checker;
719

820
class ChallengeManager
921
{
1022
const LOG_PREFIX = 'Perun:ChallengeManager: ';
23+
24+
const CONFIG_FILE_NAME = 'challenges_config.php';
25+
const HASH_ALG = 'hashAlg';
26+
const SIG_ALG = 'sigAlg';
27+
const CHALLENGE_LENGTH = 'challengeLength';
28+
const PUB_KEY = 'pubKey';
29+
const PRIV_KEY = 'privKey';
30+
1131
private $challengeDbCmd;
1232

33+
private $hashAlg;
34+
private $challengeLength;
35+
36+
private $privKey;
37+
private $pubKey;
38+
39+
1340
public function __construct()
1441
{
1542
$this->challengeDbCmd = new ChallengesDbCmd();
43+
$config = Configuration::getConfig(self::CONFIG_FILE_NAME);
44+
$this->hashAlg = $config->getString(self::HASH_ALG, 'sha512');
45+
$this->sighAlg = $config->getString(self::SIG_ALG, 'sha512');
46+
$this->challengeLength = $config->getInteger(self::CHALLENGE_LENGTH, 32);
47+
$this->pubKey = $config->getString(self::PUB_KEY);
48+
$this->privKey = $config->getString(self::PRIV_KEY);
1649
}
1750

18-
public function insertChallenge($challenge, $id, $scriptName): bool
51+
public function generateChallenge($id, $scriptName): string
1952
{
20-
if (empty($challenge) ||
21-
empty($id) ||
53+
try {
54+
$challenge = hash($this->hashAlg, random_bytes($this->challengeLength));
55+
} catch (Exception $ex) {
56+
http_response_code(500);
57+
throw new Exception('ChallengeManager.generateChallenge: Error while generating a challenge');
58+
}
59+
60+
if (empty($id) ||
2261
empty($scriptName) ||
2362
!$this->challengeDbCmd->insertChallenge($challenge, $id, $scriptName)) {
2463
Logger::error(self::LOG_PREFIX . 'Error while creating a challenge');
2564
http_response_code(500);
26-
return false;
65+
throw new Exception('ChallengeManager.generateChallenge: Error while generating a challenge');
2766
}
67+
return $challenge;
68+
}
2869

29-
return true;
70+
public function generateToken($id, $scriptName, $data)
71+
{
72+
73+
$challenge = $this->generateChallenge($id, $scriptName);
74+
75+
if (empty($challenge)) {
76+
Logger::error('Retrieving the challenge was not successful.');
77+
return;
78+
}
79+
80+
$jwk = JWKFactory::createFromKeyFile($this->privKey);
81+
$algorithmManager = new AlgorithmManager(
82+
[
83+
self::getAlgorithm('Signature\\Algorithm', $this->sighAlg)
84+
]
85+
);
86+
$jwsBuilder = new JWSBuilder($algorithmManager);
87+
$payload = json_encode([
88+
'iat' => time(),
89+
'nbf' => time(),
90+
'exp' => time() + 300,
91+
'challenge' => $challenge,
92+
'id' => $id,
93+
'data' => $data
94+
]);
95+
96+
$jws = $jwsBuilder
97+
->create()
98+
->withPayload($payload)
99+
->addSignature($jwk, ['alg' => $this->sighAlg])
100+
->build();
101+
102+
$serializer = new CompactSerializer();
103+
$token = $serializer->serialize($jws, 0);
104+
105+
return $token;
106+
}
107+
108+
public function decodeToken($token)
109+
{
110+
$algorithmManager = new AlgorithmManager(
111+
[
112+
self::getAlgorithm('Signature\\Algorithm', $this->sighAlg)
113+
]
114+
);
115+
$jwsVerifier = new JWSVerifier($algorithmManager);
116+
$jwk = JWKFactory::createFromKeyFile($this->pubKey);
117+
118+
$serializerManager = new JWSSerializerManager([new CompactSerializer()]);
119+
$jws = $serializerManager->unserialize($token);
120+
121+
$headerCheckerManager = new HeaderCheckerManager(
122+
[new AlgorithmChecker([$this->sighAlg])],
123+
[new JWSTokenSupport()]
124+
);
125+
126+
$headerCheckerManager->check($jws, 0);
127+
128+
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0);
129+
130+
if (!$isVerified) {
131+
Logger::error('Perun.updateUes: The token signature is invalid!');
132+
http_response_code(401);
133+
exit;
134+
}
135+
136+
$claimCheckerManager = new ClaimCheckerManager(
137+
[
138+
new Checker\IssuedAtChecker(),
139+
new Checker\NotBeforeChecker(),
140+
new Checker\ExpirationTimeChecker(),
141+
]
142+
);
143+
$claims = json_decode($jws->getPayload(), true);
144+
145+
$claimCheckerManager->check($claims);
146+
147+
$challenge = $claims['challenge'];
148+
$id = $claims['id'];
149+
150+
$challengeManager = new ChallengeManager();
151+
152+
$challengeDb = $challengeManager->readChallengeFromDb($id);
153+
154+
$checkAccessSucceeded = self::checkAccess($challenge, $challengeDb);
155+
$challengeSuccessfullyDeleted = $challengeManager->deleteChallengeFromDb($id);
156+
157+
if (!$checkAccessSucceeded || !$challengeSuccessfullyDeleted) {
158+
exit;
159+
}
160+
161+
return $claims;
30162
}
31163

32-
public function readChallengeFromDb($id)
164+
private function readChallengeFromDb($id)
33165
{
34166
if (empty($id)) {
35167
http_response_code(400);
@@ -45,7 +177,7 @@ public function readChallengeFromDb($id)
45177
return $result;
46178
}
47179

48-
public static function checkAccess($challenge, $challengeDb): bool
180+
private static function checkAccess($challenge, $challengeDb): bool
49181
{
50182
if (empty($challenge) || empty($challengeDb)) {
51183
http_response_code(400);
@@ -61,7 +193,7 @@ public static function checkAccess($challenge, $challengeDb): bool
61193
return true;
62194
}
63195

64-
public function deleteChallengeFromDb($id): bool
196+
private function deleteChallengeFromDb($id): bool
65197
{
66198
if (empty($id)) {
67199
http_response_code(400);
@@ -77,7 +209,7 @@ public function deleteChallengeFromDb($id): bool
77209
return true;
78210
}
79211

80-
public static function getAlgorithm($path, $className)
212+
private static function getAlgorithm($path, $className)
81213
{
82214
$classPath = sprintf('Jose\\Component\\%s\\%s', $path, $className);
83215
if (! class_exists($classPath)) {

www/getChallenge.php

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)