1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Facile\OpenIDClient\ConformanceTest; |
||||
6 | |||||
7 | use Http\Discovery\Psr17FactoryDiscovery; |
||||
8 | use Http\Discovery\Psr18ClientDiscovery; |
||||
9 | use PHPUnit\Framework\TestCase; |
||||
10 | use Psr\Container\ContainerInterface; |
||||
11 | use Psr\Http\Client\ClientInterface as HttpClient; |
||||
12 | use Psr\Http\Message\RequestFactoryInterface; |
||||
13 | use Psr\Http\Message\ServerRequestInterface; |
||||
14 | use ReflectionFunction; |
||||
15 | use Facile\OpenIDClient\Client\ClientBuilder; |
||||
16 | use Facile\OpenIDClient\Client\ClientInterface; |
||||
17 | use Facile\OpenIDClient\Client\Metadata\ClientMetadata; |
||||
18 | use Facile\OpenIDClient\Issuer\IssuerBuilder; |
||||
19 | use Laminas\Diactoros\RequestFactory; |
||||
20 | use Laminas\Diactoros\ServerRequestFactory; |
||||
21 | use Laminas\Diactoros\Uri; |
||||
22 | use RuntimeException; |
||||
23 | use Facile\OpenIDClient\Service\RegistrationService; |
||||
24 | |||||
25 | abstract class AbstractRpTestCase extends TestCase |
||||
26 | { |
||||
27 | /** @var ContainerInterface */ |
||||
28 | protected static $container; |
||||
29 | |||||
30 | public static function setUpBeforeClass(): void |
||||
31 | { |
||||
32 | parent::setUpBeforeClass(); |
||||
33 | |||||
34 | self::$container = require __DIR__ . '/../config/container.php'; |
||||
35 | } |
||||
36 | |||||
37 | public function getRootTestUri(): string |
||||
38 | { |
||||
39 | return 'https://rp.certification.openid.net:8080/'; |
||||
40 | } |
||||
41 | |||||
42 | public function getRpID(): string |
||||
43 | { |
||||
44 | return 'tmv_php-openid-client'; |
||||
45 | } |
||||
46 | |||||
47 | public function getRpUri(): string |
||||
48 | { |
||||
49 | return $this->getRootTestUri() . $this->getRpID() . '/'; |
||||
50 | } |
||||
51 | |||||
52 | public function getTestUri(string $testId): string |
||||
53 | { |
||||
54 | return $this->getRpUri() . $testId; |
||||
55 | } |
||||
56 | |||||
57 | public function getLogTestUri(string $testId): string |
||||
58 | { |
||||
59 | return $this->getRootTestUri() . 'log/' . $this->getRpID() . '/' . $testId . '.txt'; |
||||
60 | } |
||||
61 | |||||
62 | public function getRedirectUri(): string |
||||
63 | { |
||||
64 | return 'https://' . $this->getRpID() . '.dev/callback'; |
||||
65 | } |
||||
66 | |||||
67 | protected function simulateAuthRedirect(string $uri): ServerRequestInterface |
||||
68 | { |
||||
69 | /** @var HttpClient $client */ |
||||
70 | $httpClient = $this->getContainer()->has(HttpClient::class) |
||||
71 | ? $this->getContainer()->get(HttpClient::class) |
||||
72 | : Psr18ClientDiscovery::find(); |
||||
73 | $requestFactory = $this->getContainer()->has(RequestFactoryInterface::class) |
||||
74 | ? $this->getContainer()->get(RequestFactoryInterface::class) |
||||
75 | : Psr17FactoryDiscovery::findRequestFactory(); |
||||
76 | |||||
77 | $request = $requestFactory->createRequest('GET', $uri); |
||||
78 | $response = $httpClient->sendRequest($request); |
||||
79 | |||||
80 | $serverRequestFactory = new ServerRequestFactory(); |
||||
81 | |||||
82 | /** @var string $location */ |
||||
83 | $location = $response->getHeader('location')[0] ?? null; |
||||
84 | $this->assertIsString($location); |
||||
85 | |||||
86 | return $serverRequestFactory->createServerRequest('GET', $location); |
||||
87 | } |
||||
88 | |||||
89 | protected function parseQueryParams(string $uri): array |
||||
90 | { |
||||
91 | $uri = new Uri($uri); |
||||
92 | \parse_str($uri->getQuery(), $query); |
||||
93 | |||||
94 | return $query; |
||||
95 | } |
||||
96 | |||||
97 | protected function executeRpTest(string $profile, string $testName, callable $callback): void |
||||
98 | { |
||||
99 | echo $this->getClosureDump($callback); |
||||
100 | |||||
101 | $testUtil = $this->getContainer()->get(RpTestUtil::class); |
||||
0 ignored issues
–
show
Unused Code
introduced
by
![]() |
|||||
102 | |||||
103 | try { |
||||
104 | $callback($profile, $testName); |
||||
105 | } catch (\Throwable $e) { |
||||
106 | throw $e; |
||||
107 | } finally { |
||||
108 | $this->getAndSaveTestLog($profile, $testName); |
||||
109 | } |
||||
110 | } |
||||
111 | |||||
112 | public function registerClient(string $testName, array $metadata = []): ClientInterface |
||||
113 | { |
||||
114 | $registrationService = new RegistrationService(); |
||||
0 ignored issues
–
show
The call to
Facile\OpenIDClient\Serv...nService::__construct() has too few arguments starting with client .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
115 | |||||
116 | $issuerBuilder = new IssuerBuilder(); |
||||
117 | $issuer = $issuerBuilder->build($this->getTestUri($testName) . '/.well-known/openid-configuration'); |
||||
118 | |||||
119 | $clientMetadata = ClientMetadata::fromArray($registrationService->register($issuer, \array_merge([ |
||||
120 | 'redirect_uris' => [$this->getRedirectUri()], |
||||
121 | 'contacts' => [ |
||||
122 | '[email protected]', |
||||
123 | ], |
||||
124 | ], $metadata))); |
||||
125 | |||||
126 | return (new ClientBuilder()) |
||||
127 | ->setClientMetadata($clientMetadata) |
||||
128 | ->build(); |
||||
129 | } |
||||
130 | |||||
131 | protected function getClosureDump(callable $closure) |
||||
132 | { |
||||
133 | $str = 'function ('; |
||||
134 | $r = new ReflectionFunction($closure); |
||||
135 | $params = []; |
||||
136 | foreach($r->getParameters() as $p) { |
||||
137 | $s = ''; |
||||
138 | if($p->isArray()) { |
||||
139 | $s .= 'array '; |
||||
140 | } else if($p->getClass()) { |
||||
141 | $s .= $p->getClass()->name . ' '; |
||||
142 | } |
||||
143 | if($p->isPassedByReference()){ |
||||
144 | $s .= '&'; |
||||
145 | } |
||||
146 | $s .= '$' . $p->name; |
||||
147 | if($p->isOptional()) { |
||||
148 | $s .= ' = ' . var_export($p->getDefaultValue(), TRUE); |
||||
149 | } |
||||
150 | $params []= $s; |
||||
151 | } |
||||
152 | $str .= implode(', ', $params); |
||||
153 | $str .= '){' . PHP_EOL; |
||||
154 | $lines = file($r->getFileName()); |
||||
155 | for ($l = $r->getStartLine(); $l < $r->getEndLine(); $l++) { |
||||
156 | $str .= $lines[$l]; |
||||
157 | } |
||||
158 | return $str; |
||||
159 | } |
||||
160 | |||||
161 | public function getAndSaveTestLog(string $profile, string $testName): string |
||||
162 | { |
||||
163 | /** @var HttpClient $httpClient */ |
||||
164 | $httpClient = $this->getContainer()->get('httplug.clients.default'); |
||||
165 | $request = (new RequestFactory())->createRequest('GET', $this->getLogTestUri($testName)); |
||||
166 | |||||
167 | $response = $httpClient->sendRequest($request); |
||||
168 | |||||
169 | if (200 !== $response->getStatusCode()) { |
||||
170 | throw new \RuntimeException('Invalid log response status code'); |
||||
171 | } |
||||
172 | |||||
173 | $log = (string) $response->getBody(); |
||||
174 | |||||
175 | $logFilePath = __DIR__ . '/../log/' . ltrim($profile, '@') . '/' . $testName . '.txt'; |
||||
176 | $dirname = \dirname($logFilePath); |
||||
177 | |||||
178 | if (! \file_exists($dirname) && ! mkdir($concurrentDirectory = $dirname, 0777, true) && ! is_dir($concurrentDirectory)) { |
||||
179 | throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); |
||||
180 | } |
||||
181 | |||||
182 | \file_put_contents($logFilePath, $log); |
||||
183 | |||||
184 | return $log; |
||||
185 | } |
||||
186 | |||||
187 | public function getRpProfile(): ?string |
||||
188 | { |
||||
189 | $value = $this->getAnnotations()['method']['rp-profile'][0] ?? null; |
||||
0 ignored issues
–
show
The method
getAnnotations() does not exist on Facile\OpenIDClient\Conf...Test\AbstractRpTestCase .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||
190 | |||||
191 | if (! $value) { |
||||
192 | throw new RuntimeException('No rp-profile annotation set'); |
||||
193 | } |
||||
194 | |||||
195 | return $value; |
||||
196 | } |
||||
197 | |||||
198 | public function getRpTestId(): ?string |
||||
199 | { |
||||
200 | $value = $this->getAnnotations()['method']['rp-test-id'][0] ?? null; |
||||
201 | |||||
202 | if (! $value) { |
||||
203 | throw new RuntimeException('No rp-test-id annotation set'); |
||||
204 | } |
||||
205 | |||||
206 | return $value; |
||||
207 | } |
||||
208 | |||||
209 | /** |
||||
210 | * @return ContainerInterface |
||||
211 | */ |
||||
212 | public function getContainer(): ContainerInterface |
||||
213 | { |
||||
214 | return static::$container; |
||||
215 | } |
||||
216 | } |
||||
217 |