diff options
author | Marvin Borner | 2018-07-20 16:34:32 +0200 |
---|---|---|
committer | Marvin Borner | 2018-07-20 16:34:32 +0200 |
commit | 74cb1477bb921a2378ea22a552b71a48c11e0931 (patch) | |
tree | 621ab17315be667c16dad8f3d5f44d67a7a47e8f /infrastructure/Auth | |
parent | 400591b34d4b0a6288834539808a9dede8a60e3a (diff) |
Better API (integrated oauth completely)
Diffstat (limited to 'infrastructure/Auth')
-rw-r--r-- | infrastructure/Auth/AuthServiceProvider.php | 41 | ||||
-rw-r--r-- | infrastructure/Auth/Controllers/LoginController.php | 38 | ||||
-rw-r--r-- | infrastructure/Auth/Exceptions/InvalidCredentialsException.php | 13 | ||||
-rw-r--r-- | infrastructure/Auth/LoginProxy.php | 126 | ||||
-rw-r--r-- | infrastructure/Auth/Middleware/AccessTokenChecker.php | 37 | ||||
-rw-r--r-- | infrastructure/Auth/Requests/LoginRequest.php | 21 | ||||
-rw-r--r-- | infrastructure/Auth/routes_protected.php | 3 | ||||
-rw-r--r-- | infrastructure/Auth/routes_public.php | 4 |
8 files changed, 283 insertions, 0 deletions
diff --git a/infrastructure/Auth/AuthServiceProvider.php b/infrastructure/Auth/AuthServiceProvider.php new file mode 100644 index 0000000..944f812 --- /dev/null +++ b/infrastructure/Auth/AuthServiceProvider.php @@ -0,0 +1,41 @@ +<?php + +namespace Infrastructure\Auth; + +use Carbon\Carbon; +use Laravel\Passport\Passport; +use Illuminate\Support\Facades\Gate; +use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; + +class AuthServiceProvider extends ServiceProvider +{ + /** + * The policy mappings for the application. + * + * @var array + */ + protected $policies = [ + 'App\Model' => 'App\Policies\ModelPolicy', + ]; + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + Passport::routes(function ($router) { + $router->forAccessTokens(); + // Uncomment for allowing personal access tokens + // $router->forPersonalAccessTokens(); + $router->forTransientTokens(); + }); + + Passport::tokensExpireIn(Carbon::now()->addMinutes(10)); + + Passport::refreshTokensExpireIn(Carbon::now()->addDays(10)); + } +}
\ No newline at end of file diff --git a/infrastructure/Auth/Controllers/LoginController.php b/infrastructure/Auth/Controllers/LoginController.php new file mode 100644 index 0000000..a72f8a0 --- /dev/null +++ b/infrastructure/Auth/Controllers/LoginController.php @@ -0,0 +1,38 @@ +<?php + +namespace Infrastructure\Auth\Controllers; + +use Illuminate\Http\Request; +use Infrastructure\Auth\LoginProxy; +use Infrastructure\Auth\Requests\LoginRequest; +use Infrastructure\Http\Controller; + +class LoginController extends Controller +{ + private $loginProxy; + + public function __construct(LoginProxy $loginProxy) + { + $this->loginProxy = $loginProxy; + } + + public function login(LoginRequest $request) + { + $email = $request->get('email'); + $password = $request->get('password'); + + return $this->response($this->loginProxy->attemptLogin($email, $password)); + } + + public function refresh(Request $request) + { + return $this->response($this->loginProxy->attemptRefresh()); + } + + public function logout() + { + $this->loginProxy->logout(); + + return $this->response(null, 204); + } +}
\ No newline at end of file diff --git a/infrastructure/Auth/Exceptions/InvalidCredentialsException.php b/infrastructure/Auth/Exceptions/InvalidCredentialsException.php new file mode 100644 index 0000000..45a8b6e --- /dev/null +++ b/infrastructure/Auth/Exceptions/InvalidCredentialsException.php @@ -0,0 +1,13 @@ +<?php + +namespace Infrastructure\Auth\Exceptions; + +use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; + +class InvalidCredentialsException extends UnauthorizedHttpException +{ + public function __construct($message = null, \Exception $previous = null, $code = 0) + { + parent::__construct('', $message, $previous, $code); + } +}
\ No newline at end of file diff --git a/infrastructure/Auth/LoginProxy.php b/infrastructure/Auth/LoginProxy.php new file mode 100644 index 0000000..11783f0 --- /dev/null +++ b/infrastructure/Auth/LoginProxy.php @@ -0,0 +1,126 @@ +<?php + +namespace Infrastructure\Auth; + +use Illuminate\Foundation\Application; +use Infrastructure\Auth\Exceptions\InvalidCredentialsException; +use Api\Users\Repositories\UserRepository; + +class LoginProxy +{ + const REFRESH_TOKEN = 'refreshToken'; + + private $apiConsumer; + + private $auth; + + private $cookie; + + private $db; + + private $request; + + private $userRepository; + + public function __construct(Application $app, UserRepository $userRepository) { + $this->userRepository = $userRepository; + + $this->apiConsumer = $app->make('apiconsumer'); + $this->auth = $app->make('auth'); + $this->cookie = $app->make('cookie'); + $this->db = $app->make('db'); + $this->request = $app->make('request'); + } + + /** + * Attempt to create an access token using user credentials + * + * @param string $email + * @param string $password + */ + public function attemptLogin($email, $password) + { + $user = $this->userRepository->getWhere('email', $email)->first(); + + if (!is_null($user)) { + return $this->proxy('password', [ + 'username' => $email, + 'password' => $password + ]); + } + + throw new InvalidCredentialsException(); + } + + /** + * Attempt to refresh the access token used a refresh token that + * has been saved in a cookie + */ + public function attemptRefresh() + { + $refreshToken = $this->request->cookie(self::REFRESH_TOKEN); + + return $this->proxy('refresh_token', [ + 'refresh_token' => $refreshToken + ]); + } + + /** + * Proxy a request to the OAuth server. + * + * @param string $grantType what type of grant type should be proxied + * @param array $data the data to send to the server + */ + public function proxy($grantType, array $data = []) + { + $data = array_merge($data, [ + 'client_id' => env('PASSWORD_CLIENT_ID'), + 'client_secret' => env('PASSWORD_CLIENT_SECRET'), + 'grant_type' => $grantType + ]); + + $response = $this->apiConsumer->post('/oauth/token', $data); + + if (!$response->isSuccessful()) { + throw new InvalidCredentialsException(); + } + + $data = json_decode($response->getContent()); + + // Create a refresh token cookie + $this->cookie->queue( + self::REFRESH_TOKEN, + $data->refresh_token, + 864000, // 10 days + null, + null, + false, + true // HttpOnly + ); + + return [ + 'access_token' => $data->access_token, + 'expires_in' => $data->expires_in + ]; + } + + /** + * Logs out the user. We revoke access token and refresh token. + * Also instruct the client to forget the refresh cookie. + */ + public function logout() + { + $accessToken = $this->auth->user()->token(); + + $refreshToken = $this->db + ->table('oauth_refresh_tokens') + ->where('access_token_id', $accessToken->id) + ->update([ + 'revoked' => true + ]); + + $accessToken->revoke(); + + $this->cookie->queue($this->cookie->forget(self::REFRESH_TOKEN)); + } +} diff --git a/infrastructure/Auth/Middleware/AccessTokenChecker.php b/infrastructure/Auth/Middleware/AccessTokenChecker.php new file mode 100644 index 0000000..f79f5cb --- /dev/null +++ b/infrastructure/Auth/Middleware/AccessTokenChecker.php @@ -0,0 +1,37 @@ +<?php + +namespace Infrastructure\Auth\Middleware; + +use Closure; +use Illuminate\Foundation\Application; +use Illuminate\Auth\Middleware\Authenticate; +use Illuminate\Auth\AuthenticationException; +use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; + +class AccessTokenChecker +{ + private $app; + + private $oAuthMiddleware; + + public function __construct( + Application $app, + Authenticate $authenticate + ) { + $this->app = $app; + $this->authenticate = $authenticate; + } + + public function handle($request, Closure $next, $scopesString = null) + { + if ($this->app->environment() !== 'testing') { + try { + return $this->authenticate->handle($request, $next, 'api'); + } catch (AuthenticationException $e) { + throw new UnauthorizedHttpException('Challenge'); + } + } + + return $next($request); + } +} diff --git a/infrastructure/Auth/Requests/LoginRequest.php b/infrastructure/Auth/Requests/LoginRequest.php new file mode 100644 index 0000000..5c5a3bb --- /dev/null +++ b/infrastructure/Auth/Requests/LoginRequest.php @@ -0,0 +1,21 @@ +<?php + +namespace Infrastructure\Auth\Requests; + +use Infrastructure\Http\ApiRequest; + +class LoginRequest extends ApiRequest +{ + public function authorize() + { + return true; + } + + public function rules() + { + return [ + 'email' => 'required|email', + 'password' => 'required' + ]; + } +} diff --git a/infrastructure/Auth/routes_protected.php b/infrastructure/Auth/routes_protected.php new file mode 100644 index 0000000..0fe814f --- /dev/null +++ b/infrastructure/Auth/routes_protected.php @@ -0,0 +1,3 @@ +<?php + +$router->post('/logout', 'LoginController@logout');
\ No newline at end of file diff --git a/infrastructure/Auth/routes_public.php b/infrastructure/Auth/routes_public.php new file mode 100644 index 0000000..79f5b51 --- /dev/null +++ b/infrastructure/Auth/routes_public.php @@ -0,0 +1,4 @@ +<?php + +$router->post('/login', 'LoginController@login'); +$router->post('/login/refresh', 'LoginController@refresh');
\ No newline at end of file |