1 | <?php |
||
2 | |||
3 | namespace kalanis\OAuth2\DI; |
||
4 | |||
5 | |||
6 | use kalanis\OAuth2\Storage; |
||
7 | use Nette\Bootstrap\Configurator; |
||
8 | use Nette\DI\CompilerExtension; |
||
9 | use Nette\DI\ContainerBuilder; |
||
10 | use Nette\DI\Definitions\Definition; |
||
11 | |||
12 | |||
13 | /** |
||
14 | * OAuth2 compiler extension |
||
15 | * @package kalanis\OAuth2\DI |
||
16 | */ |
||
17 | class Extension extends CompilerExtension |
||
18 | { |
||
19 | |||
20 | /** |
||
21 | * @var array<string, array{ |
||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||
22 | * accessTokenStorage: class-string<Storage\AccessTokens\IAccessTokenStorage>, |
||
23 | * authorizationCodeStorage: class-string<Storage\AuthorizationCodes\IAuthorizationCodeStorage>, |
||
24 | * clientStorage: class-string<Storage\Clients\IClientStorage>, |
||
25 | * refreshTokenStorage: class-string<Storage\RefreshTokens\IRefreshTokenStorage>, |
||
26 | * }> |
||
27 | */ |
||
28 | protected array $storages = [ |
||
29 | 'ndb' => [ |
||
30 | 'accessTokenStorage' => Storage\NDB\AccessTokenStorage::class, |
||
31 | 'authorizationCodeStorage' => Storage\NDB\AuthorizationCodeStorage::class, |
||
32 | 'clientStorage' => Storage\NDB\ClientStorage::class, |
||
33 | 'refreshTokenStorage' => Storage\NDB\RefreshTokenStorage::class, |
||
34 | ], |
||
35 | 'dibi' => [ |
||
36 | 'accessTokenStorage' => Storage\Dibi\AccessTokenStorage::class, |
||
37 | 'authorizationCodeStorage' => Storage\Dibi\AuthorizationCodeStorage::class, |
||
38 | 'clientStorage' => Storage\Dibi\ClientStorage::class, |
||
39 | 'refreshTokenStorage' => Storage\Dibi\RefreshTokenStorage::class, |
||
40 | ], |
||
41 | ]; |
||
42 | |||
43 | /** |
||
44 | * Default DI settings |
||
45 | * @var array<string, string|int|null> |
||
46 | */ |
||
47 | protected array $defaults = [ |
||
48 | 'accessTokenStorage' => null, |
||
49 | 'authorizationCodeStorage' => null, |
||
50 | 'clientStorage' => null, |
||
51 | 'refreshTokenStorage' => null, |
||
52 | 'accessTokenLifetime' => 3600, // 1 hour |
||
53 | 'refreshTokenLifetime' => 36000, // 10 hours |
||
54 | 'authorizationCodeLifetime' => 360, // 6 minutes |
||
55 | 'storage' => null, |
||
56 | ]; |
||
57 | |||
58 | /** |
||
59 | * Register OAuth2 extension |
||
60 | */ |
||
61 | public static function install(Configurator $configurator): void |
||
62 | { |
||
63 | $configurator->onCompile[] = function ($configurator, $compiler): void { |
||
64 | $compiler->addExtension('oauth2', new Extension); |
||
65 | }; |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Load DI configuration |
||
70 | */ |
||
71 | public function loadConfiguration(): void |
||
72 | { |
||
73 | 1 | $container = $this->getContainerBuilder(); |
|
74 | 1 | $passedConf = $this->getConfig(); |
|
75 | 1 | $passedConf = is_object($passedConf) ? $this->propertiesFromConfig($passedConf) : (array) $passedConf; |
|
76 | 1 | $config = array_merge($this->defaults, $passedConf); |
|
77 | |||
78 | // Library common |
||
79 | 1 | $container->addDefinition($this->prefix('keyGenerator')) |
|
80 | 1 | ->setType(\kalanis\OAuth2\KeyGenerator::class); |
|
81 | |||
82 | 1 | $container->addDefinition($this->prefix('input')) |
|
83 | 1 | ->setType(\kalanis\OAuth2\Http\Input::class); |
|
84 | |||
85 | // Grant types |
||
86 | 1 | $container->addDefinition($this->prefix('authorizationCodeGrant')) |
|
87 | 1 | ->setType(\kalanis\OAuth2\Grant\AuthorizationCode::class); |
|
88 | 1 | $container->addDefinition($this->prefix('refreshTokenGrant')) |
|
89 | 1 | ->setType(\kalanis\OAuth2\Grant\RefreshToken::class); |
|
90 | 1 | $container->addDefinition($this->prefix('passwordGrant')) |
|
91 | 1 | ->setType(\kalanis\OAuth2\Grant\Password::class); |
|
92 | 1 | $container->addDefinition($this->prefix('implicitGrant')) |
|
93 | 1 | ->setType(\kalanis\OAuth2\Grant\Implicit::class); |
|
94 | 1 | $container->addDefinition($this->prefix('clientCredentialsGrant')) |
|
95 | 1 | ->setType(\kalanis\OAuth2\Grant\ClientCredentials::class); |
|
96 | |||
97 | 1 | $container->addDefinition($this->prefix('grantContext')) |
|
98 | 1 | ->setType(\kalanis\OAuth2\Grant\GrantContext::class) |
|
99 | 1 | ->addSetup('$service->addGrantType(?)', [$this->prefix('@authorizationCodeGrant')]) |
|
100 | 1 | ->addSetup('$service->addGrantType(?)', [$this->prefix('@refreshTokenGrant')]) |
|
101 | 1 | ->addSetup('$service->addGrantType(?)', [$this->prefix('@passwordGrant')]) |
|
102 | 1 | ->addSetup('$service->addGrantType(?)', [$this->prefix('@implicitGrant')]) |
|
103 | 1 | ->addSetup('$service->addGrantType(?)', [$this->prefix('@clientCredentialsGrant')]); |
|
104 | |||
105 | // Tokens |
||
106 | 1 | $container->addDefinition($this->prefix('accessToken')) |
|
107 | 1 | ->setType(\kalanis\OAuth2\Storage\AccessTokens\AccessTokenFacade::class) |
|
108 | 1 | ->setArguments([$config['accessTokenLifetime']]); |
|
109 | 1 | $container->addDefinition($this->prefix('refreshToken')) |
|
110 | 1 | ->setType(\kalanis\OAuth2\Storage\RefreshTokens\RefreshTokenFacade::class) |
|
111 | 1 | ->setArguments([$config['refreshTokenLifetime']]); |
|
112 | 1 | $container->addDefinition($this->prefix('authorizationCode')) |
|
113 | 1 | ->setType(\kalanis\OAuth2\Storage\AuthorizationCodes\AuthorizationCodeFacade::class) |
|
114 | 1 | ->setArguments([$config['authorizationCodeLifetime']]); |
|
115 | |||
116 | 1 | $container->addDefinition('tokenContext') |
|
117 | 1 | ->setType(\kalanis\OAuth2\Storage\TokenContext::class) |
|
118 | 1 | ->addSetup('$service->addToken(?)', [$this->prefix('@accessToken')]) |
|
119 | 1 | ->addSetup('$service->addToken(?)', [$this->prefix('@refreshToken')]) |
|
120 | 1 | ->addSetup('$service->addToken(?)', [$this->prefix('@authorizationCode')]); |
|
121 | |||
122 | // Default fallback value |
||
123 | 1 | $storageIndex = 'ndb'; |
|
124 | |||
125 | // Nette database Storage |
||
126 | 1 | if ('DIBI' == strtoupper(strval($config['storage'])) || (is_null($config['storage']) && $this->getByType($container, 'DibiConnection'))) { |
|
127 | $storageIndex = 'dibi'; |
||
128 | } |
||
129 | |||
130 | // Nette database Storage |
||
131 | 1 | $container->addDefinition($this->prefix('accessTokenStorage')) |
|
132 | 1 | ->setType($config['accessTokenStorage'] ?: $this->storages[$storageIndex]['accessTokenStorage']); |
|
133 | 1 | $container->addDefinition($this->prefix('refreshTokenStorage')) |
|
134 | 1 | ->setType($config['refreshTokenStorage'] ?: $this->storages[$storageIndex]['refreshTokenStorage']); |
|
135 | 1 | $container->addDefinition($this->prefix('authorizationCodeStorage')) |
|
136 | 1 | ->setType($config['authorizationCodeStorage'] ?: $this->storages[$storageIndex]['authorizationCodeStorage']); |
|
137 | 1 | $container->addDefinition($this->prefix('clientStorage')) |
|
138 | 1 | ->setType($config['clientStorage'] ?: $this->storages[$storageIndex]['clientStorage']); |
|
139 | 1 | } |
|
140 | |||
141 | /** |
||
142 | * @param object $config |
||
143 | * @return array<string, mixed> |
||
144 | */ |
||
145 | private function propertiesFromConfig(object $config): array |
||
146 | { |
||
147 | $result = []; |
||
148 | $obj = new \ReflectionObject($config); |
||
149 | foreach ($obj->getProperties() as $property) { |
||
150 | if ($property->isPublic()) { |
||
151 | $result[$property->getName()] = $property->getValue(); |
||
152 | } |
||
153 | } |
||
154 | return $result; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * @param ContainerBuilder $container |
||
159 | * @param string $type |
||
160 | * @return Definition|null |
||
161 | */ |
||
162 | private function getByType(ContainerBuilder $container, string $type): ?Definition |
||
163 | { |
||
164 | 1 | $definitions = $container->getDefinitions(); |
|
165 | 1 | foreach ($definitions as $definition) { |
|
166 | 1 | if (isset($definition->class) && $definition->class === $type) { |
|
167 | return $definition; |
||
0 ignored issues
–
show
|
|||
168 | } |
||
169 | } |
||
170 | 1 | return null; |
|
171 | } |
||
172 | } |
||
173 |