From ba6b03bea4c3e4f96cf66e92f7ec7e10602bb09e Mon Sep 17 00:00:00 2001 From: Johan Steen Date: Mon, 3 Aug 2015 09:21:23 +0700 Subject: [PATCH] Updates responses to use the refactored responses --- api/app/Http/Controllers/AuthController.php | 117 ++++++++++++++++++-- api/tests/integration/AuthTest.php | 4 +- 2 files changed, 112 insertions(+), 9 deletions(-) diff --git a/api/app/Http/Controllers/AuthController.php b/api/app/Http/Controllers/AuthController.php index 5789463d..ff8b1fa4 100644 --- a/api/app/Http/Controllers/AuthController.php +++ b/api/app/Http/Controllers/AuthController.php @@ -2,19 +2,33 @@ namespace App\Http\Controllers; -use App; +use Log; use RuntimeException; use Tymon\JWTAuth\JWTAuth; +use App\Models\SocialLogin; use Illuminate\Http\Request; use App\Repositories\UserRepository; use App\Exceptions\BadRequestException; use App\Exceptions\UnauthorizedException; use Tymon\JWTAuth\Exceptions\JWTException; +use App\Exceptions\NotImplementedException; use Illuminate\Contracts\Auth\Guard as Auth; use App\Http\Transformers\AuthTokenTransformer; +use App\Exceptions\UnprocessableEntityException; +use Illuminate\Contracts\Foundation\Application; +use App\Extensions\Socialite\Parsers\ParserFactory; +use Laravel\Socialite\Contracts\Factory as Socialite; +use Illuminate\Database\Eloquent\ModelNotFoundException; class AuthController extends ApiController { + /** + * The application instance. + * + * @var Application + */ + protected $app; + /** * JWT Auth Package. * @@ -32,15 +46,19 @@ class AuthController extends ApiController /** * Assign dependencies. * - * @param Auth $auth - * @param JWTAuth $jwtAuth + * @param Auth $auth + * @param JWTAuth $jwtAuth * @param AuthTokenTransformer $transformer + * @param Application $app + * + * @return void */ - public function __construct(Auth $auth, JWTAuth $jwtAuth, AuthTokenTransformer $transformer) + public function __construct(Auth $auth, JWTAuth $jwtAuth, AuthTokenTransformer $transformer, Application $app) { $this->auth = $auth; $this->jwtAuth = $jwtAuth; $this->transformer = $transformer; + $this->app = $app; } /** @@ -62,7 +80,7 @@ public function login(Request $request) } try { - $token = $this->jwtAuth->fromUser($this->auth->user()); + $token = $this->jwtAuth->fromUser($this->auth->user(), ['method' => 'password']); } catch (JWTException $e) { throw new RuntimeException($e->getMessage(), 500, $e); } @@ -92,8 +110,11 @@ public function refresh(Request $request) /** * Login with a single use token. * - * @param Request $request - * @param \App\Repositories\UserRepository $userRepository + * @param Request $request + * @param UserRepository $userRepository + * + * @throws BadRequestException + * @throws UnauthorizedException * * @return Response */ @@ -115,4 +136,86 @@ public function token(Request $request, UserRepository $userRepository) return $this->getResponse()->item($token, $this->transformer); } + + /** + * Redirect the user to the Provider authentication page. + * + * @param string $provider + * @param Socialite $socialite + * + * @return Response + */ + public function redirectToProvider($provider, Socialite $socialite) + { + $this->validateProvider($provider); + + return $socialite->with($provider)->redirect(); + } + + /** + * Obtain the user information from Provider. + * + * @param string $provider + * @param Socialite $socialite + * @param UserRepository $repository + * + * @throws UnprocessableEntityException + * + * @return Response + */ + public function handleProviderCallback($provider, Socialite $socialite, UserRepository $repository) + { + $this->validateProvider($provider); + + $socialUser = $socialite->with($provider)->user(); + + // Verify so we received an email address, if using oAuth credentials + // with Twitter for instance, that isn't whitelisted, no email + // address will be returned with the response. + // See the notes in Spira API doc under Social Login for more info. + if (!$socialUser->email) { + // The app is connected with the service, but the 3rd party service + // is not configured or allowed to return email addresses, so we + // can't process the data further. Let's throw an exception. + Log::critical('Provider '.$provider.' does not return email.'); + throw new UnprocessableEntityException('User object has no email'); + } + + // Parse the social user to fit within Spira's user model + $socialUser = ParserFactory::parse($socialUser, $provider); + + // Get or create the Spira user from the social login + try { + $user = $repository->findByEmail($socialUser->email); + } catch (ModelNotFoundException $e) { + $user = $repository->getNewModel(); + $user->fill(array_merge($socialUser->toArray(), ['user_type' => 'guest'])); + $user = $repository->save($user); + } + + $socialLogin = new SocialLogin(['provider' => $provider, 'token' => $socialUser->token]); + $user->addSocialLogin($socialLogin); + + // Prepare response data + $token = $this->jwtAuth->fromUser($user, ['method' => $provider]); + $returnUrl = $socialite->with($provider)->getCachedReturnUrl(); + + return $this->getResponse()->redirect($returnUrl, 302, ['Authorization-Update' => 'Bearer '.$token]); + } + + /** + * Check so the provider exists. + * + * @param string $provider + * + * @throws NotImplementedException + * + * @return void + */ + protected function validateProvider($provider) + { + if (!in_array($provider, array_keys($this->app['config']['services']))) { + throw new NotImplementedException('Provider '.$provider.' is not supported.'); + } + } } diff --git a/api/tests/integration/AuthTest.php b/api/tests/integration/AuthTest.php index 079efd74..291484e8 100644 --- a/api/tests/integration/AuthTest.php +++ b/api/tests/integration/AuthTest.php @@ -398,7 +398,7 @@ public function testProviderCallbackExistingUser() $this->assertResponseStatus(302); $array = json_decode($this->response->getContent(), true); $this->assertEquals('facebook', $decoded['method']); - $this->assertTrue($this->response->headers->has('location')); + $this->assertTrue($this->response->headers->has('location'), 'Response has location header.'); $this->assertEquals('http://foo.bar', $this->response->headers->get('location')); // Assert that the social login was created @@ -436,7 +436,7 @@ public function testProviderCallbackNewUser() $this->assertResponseStatus(302); $array = json_decode($this->response->getContent(), true); $this->assertEquals('facebook', $decoded['method']); - $this->assertTrue($this->response->headers->has('location')); + $this->assertTrue($this->response->headers->has('location'), 'Response has location header.'); $this->assertEquals('http://foo.bar', $this->response->headers->get('location')); // Assert that the social login was created