Skip to content

Commit 95af086

Browse files
author
rokde
committed
routes and Controller added
1 parent 7dacf72 commit 95af086

File tree

4 files changed

+222
-1
lines changed

4 files changed

+222
-1
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"require": {
1919
"php": "^7.0",
2020
"guzzlehttp/guzzle": "~6.0",
21-
"laravel/passport": "~1.0"
21+
"laravel/passport": "~1.0",
22+
"ipunkt/laravel-package-manager": "^0.1.1"
2223
},
2324
"autoload": {
2425
"psr-4": {

routes/web.php

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
Route::group(['namespace' => '\Ipunkt\Laravel\OAuthIntrospection\Http\Controllers'], function ($router) {
4+
$router->post('/oauth/introspect', 'IntrospectionController@introspectToken');
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
<?php
2+
3+
namespace Ipunkt\Laravel\OAuthIntrospection\Http\Controllers;
4+
5+
use Illuminate\Http\JsonResponse;
6+
use Laravel\Passport\Bridge\AccessTokenRepository;
7+
use Laravel\Passport\Passport;
8+
use Lcobucci\JWT\Parser;
9+
use Lcobucci\JWT\Token;
10+
use Lcobucci\JWT\ValidationData;
11+
use League\OAuth2\Server\Exception\OAuthServerException;
12+
use League\OAuth2\Server\ResourceServer;
13+
use Psr\Http\Message\ResponseInterface;
14+
use Psr\Http\Message\ServerRequestInterface;
15+
use Zend\Diactoros\Response as Psr7Response;
16+
17+
class IntrospectionController
18+
{
19+
/**
20+
* @var \Lcobucci\JWT\Parser
21+
*/
22+
private $jwt;
23+
24+
/**
25+
* @var \League\OAuth2\Server\ResourceServer
26+
*/
27+
private $resourceServer;
28+
29+
/**
30+
* @var \Laravel\Passport\Bridge\AccessTokenRepository
31+
*/
32+
private $accessTokenRepository;
33+
34+
/**
35+
* constructing IntrospectionController
36+
*
37+
* @param \Lcobucci\JWT\Parser $jwt
38+
* @param \League\OAuth2\Server\ResourceServer $resourceServer
39+
* @param \Laravel\Passport\Bridge\AccessTokenRepository $accessTokenRepository
40+
*/
41+
public function __construct(
42+
Parser $jwt,
43+
ResourceServer $resourceServer,
44+
AccessTokenRepository $accessTokenRepository
45+
) {
46+
$this->jwt = $jwt;
47+
$this->resourceServer = $resourceServer;
48+
$this->accessTokenRepository = $accessTokenRepository;
49+
}
50+
51+
/**
52+
* Authorize a client to access the user's account.
53+
*
54+
* @param ServerRequestInterface $request
55+
*
56+
* @return JsonResponse|ResponseInterface
57+
*/
58+
public function introspectToken(ServerRequestInterface $request)
59+
{
60+
try {
61+
$this->resourceServer->validateAuthenticatedRequest($request);
62+
63+
if (array_get($request->getParsedBody(), 'token_type_hint', 'access_token') !== 'access_token') {
64+
// unsupported introspection
65+
return $this->notActiveResponse();
66+
}
67+
68+
$accessToken = array_get($request->getParsedBody(), 'token');
69+
if ($accessToken === null) {
70+
return $this->notActiveResponse();
71+
}
72+
73+
$token = $this->jwt->parse($accessToken);
74+
if ( ! $this->verifyToken($token)) {
75+
return $this->errorResponse([
76+
'error' => [
77+
'title' => 'Token invalid'
78+
]
79+
]);
80+
}
81+
82+
/** @var string $userModel */
83+
$userModel = config('auth.providers.users.model');
84+
$user = (new $userModel)->findOrFail($token->getClaim('sub'));
85+
86+
return $this->jsonResponse([
87+
'active' => true,
88+
'scope' => trim(implode(' ', (array)$token->getClaim('scopes', []))),
89+
'client_id' => intval($token->getClaim('aud')),
90+
'username' => $user->email,
91+
'token_type' => 'access_token',
92+
'exp' => intval($token->getClaim('exp')),
93+
'iat' => intval($token->getClaim('iat')),
94+
'nbf' => intval($token->getClaim('nbf')),
95+
'sub' => intval($token->getClaim('sub')),
96+
'aud' => intval($token->getClaim('aud')),
97+
'jti' => $token->getClaim('jti'),
98+
]);
99+
} catch (OAuthServerException $oAuthServerException) {
100+
return $oAuthServerException->generateHttpResponse(new Psr7Response);
101+
} catch (\Exception $exception) {
102+
return $this->exceptionResponse($exception);
103+
}
104+
}
105+
106+
/**
107+
* returns inactive token message
108+
*
109+
* @return \Illuminate\Http\JsonResponse
110+
*/
111+
private function notActiveResponse(): JsonResponse
112+
{
113+
return $this->jsonResponse(['active' => false]);
114+
}
115+
116+
/**
117+
* @param array|mixed $data
118+
* @param int $status
119+
*
120+
* @return \Illuminate\Http\JsonResponse
121+
*/
122+
private function jsonResponse($data, $status = 200): JsonResponse
123+
{
124+
return new JsonResponse($data, $status);
125+
}
126+
127+
private function verifyToken(Token $token): bool
128+
{
129+
$signer = new \Lcobucci\JWT\Signer\Rsa\Sha256();
130+
$publicKey = 'file://' . Passport::keyPath('oauth-public.key');
131+
132+
try {
133+
if ( ! $token->verify($signer, $publicKey)) {
134+
return false;
135+
}
136+
137+
$data = new ValidationData();
138+
$data->setCurrentTime(time());
139+
140+
if ( ! $token->validate($data)) {
141+
return false;
142+
}
143+
144+
// is token revoked?
145+
if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) {
146+
return false;
147+
}
148+
149+
return true;
150+
} catch (\Exception $exception) {
151+
}
152+
153+
return false;
154+
}
155+
156+
/**
157+
* @param array $data
158+
* @param int $status
159+
*
160+
* @return \Illuminate\Http\JsonResponse
161+
*/
162+
private function errorResponse($data, $status = 400): JsonResponse
163+
{
164+
return $this->jsonResponse($data, $status);
165+
}
166+
167+
/**
168+
* returns an error
169+
*
170+
* @param \Exception $exception
171+
* @param int $status
172+
*
173+
* @return \Illuminate\Http\JsonResponse
174+
*/
175+
private function exceptionResponse(\Exception $exception, $status = 500): JsonResponse
176+
{
177+
return $this->errorResponse([
178+
'error' => [
179+
'id' => str_slug(get_class($exception) . ' ' . $status),
180+
'status' => $status,
181+
'title' => $exception->getMessage(),
182+
'detail' => $exception->getTraceAsString()
183+
],
184+
], $status);
185+
}
186+
}
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Ipunkt\Laravel\OAuthIntrospection;
4+
5+
use Ipunkt\Laravel\PackageManager\PackageServiceProvider;
6+
use Ipunkt\Laravel\PackageManager\Support\DefinesRoutes;
7+
8+
class OAuthIntrospectionServiceProvider extends PackageServiceProvider implements DefinesRoutes
9+
{
10+
/**
11+
* returns routes.php file (absolute path)
12+
*
13+
* @return string
14+
*/
15+
public function routesFile()
16+
{
17+
return __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'routes' . DIRECTORY_SEPARATOR . 'web.php';
18+
}
19+
20+
/**
21+
* returns namespace of package
22+
*
23+
* @return string
24+
*/
25+
protected function namespace()
26+
{
27+
return 'oauth-introspection';
28+
}
29+
}

0 commit comments

Comments
 (0)