├── composer.json └── src ├── Events ├── .gitkeep ├── UserHasLoggedIn.php ├── UserHasRegistered.php ├── UserHasRequestedPasswordReset.php ├── UserHasResetPassword.php ├── UserIsLoggingIn.php ├── UserIsLoggingOut.php └── UserIsRegistering.php ├── Exceptions ├── .gitkeep ├── ActionAbortedException.php ├── IdSiteException.php └── SocialLoginException.php ├── Http ├── Controllers │ ├── ChangePasswordController.php │ ├── ForgotPasswordController.php │ ├── IdSiteController.php │ ├── LoginController.php │ ├── MeController.php │ ├── OauthController.php │ ├── RegisterController.php │ └── SocialCallbackController.php ├── Helpers │ ├── IdSiteModel.php │ ├── IdSiteRequest.php │ ├── IdSiteSessionHelper.php │ └── PasswordPolicies.php ├── Middleware │ ├── Authenticate.php │ ├── Produces.php │ └── RedirectIfAuthenticated.php ├── Traits │ ├── AuthenticatesUser.php │ └── Cookies.php ├── routes.php └── socialRoutes.php ├── Support └── StormpathLaravelServiceProvider.php ├── config └── stormpath.php └── views ├── base.blade.php ├── change-password.blade.php ├── forgot-password.blade.php ├── login.blade.php ├── partials ├── _loginStatusMessages.blade.php ├── login │ ├── created.blade.php │ ├── forgot.blade.php │ ├── reset.blade.php │ ├── unverified.blade.php │ └── verified.blade.php └── social │ ├── facebook-login-form.blade.php │ ├── github-login-form.blade.php │ ├── google-login-form.blade.php │ ├── linkedin-login-form.blade.php │ └── main.blade.php └── register.blade.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stormpath/laravel", 3 | "description": "Build simple, secure web applications with Stormpath and Laravel!", 4 | "license": "Apache-2.0", 5 | "type": "laravel-package", 6 | "keywords": [ 7 | "users", 8 | "laravel", 9 | "accounts", 10 | "stormpath", 11 | "authorization", 12 | "authentication" 13 | ], 14 | "authors": [ 15 | { 16 | "name": "Brian Retterer", 17 | "email": "brian@stormpath.com", 18 | "homepage": "https://stormpath.com", 19 | "role": "PHP Developer Evangelist" 20 | } 21 | ], 22 | "require": { 23 | "php": ">=5.5", 24 | "stormpath/sdk": "~1.14", 25 | "illuminate/http": "~5.1|~5.2", 26 | "illuminate/routing": "~5.1|~5.2", 27 | "illuminate/validation": "~5.1|~5.2", 28 | "illuminate/support": "~5.1|~5.2", 29 | "bretterer/iso_duration_converter": "^0.1.0" 30 | }, 31 | "require-dev": { 32 | "phpunit/phpunit": "~4.0", 33 | "mockery/mockery": "~0.9", 34 | "orchestra/testbench": "~3.2.0" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "Stormpath\\Laravel\\": "src/" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "Stormpath\\Laravel\\Tests\\": "tests/" 44 | } 45 | }, 46 | "support": { 47 | "source": "https://github.com/stormpath/stormpath-laravel", 48 | "email": "support@stormpath.com", 49 | "irc": "irc://irc.freenode.org/stormpath", 50 | "issues": "https://github.com/stormpath/stormpath-laravel/issues", 51 | "docs": "http://docs.stormpath.com/php/laravel/latest/" 52 | }, 53 | "replace": { 54 | "stormpath/laravel-auth": "self.version" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Events/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stormpath/stormpath-laravel/ef4e76b6ecd368e0bbd5aa461e4de0faa7afefff/src/Events/.gitkeep -------------------------------------------------------------------------------- /src/Events/UserHasLoggedIn.php: -------------------------------------------------------------------------------- 1 | account = $account; 24 | } 25 | 26 | /** 27 | * Get the account associated with this event 28 | * 29 | * @return Account The account associated with this event 30 | */ 31 | public function getAccount() 32 | { 33 | return $this->account; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Events/UserHasRegistered.php: -------------------------------------------------------------------------------- 1 | account = $account; 24 | } 25 | 26 | /** 27 | * Get the account associated with this event 28 | * 29 | * @return Account The account associated with this event 30 | */ 31 | public function getAccount() 32 | { 33 | return $this->account; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Events/UserHasRequestedPasswordReset.php: -------------------------------------------------------------------------------- 1 | data = $data; 23 | } 24 | 25 | /** 26 | * Get the form data provided with this event 27 | * 28 | * @return array The form data 29 | */ 30 | public function getData() 31 | { 32 | return $this->data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Events/UserHasResetPassword.php: -------------------------------------------------------------------------------- 1 | data = $data; 23 | } 24 | 25 | /** 26 | * Get the form data provided with this event 27 | * 28 | * @return array The form data 29 | */ 30 | public function getData() 31 | { 32 | return $this->data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Events/UserIsLoggingOut.php: -------------------------------------------------------------------------------- 1 | data = $data; 23 | } 24 | 25 | /** 26 | * Get the form data provided with this event 27 | * 28 | * @return array The form data 29 | */ 30 | public function getData() 31 | { 32 | return $this->data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Exceptions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stormpath/stormpath-laravel/ef4e76b6ecd368e0bbd5aa461e4de0faa7afefff/src/Exceptions/.gitkeep -------------------------------------------------------------------------------- /src/Exceptions/ActionAbortedException.php: -------------------------------------------------------------------------------- 1 | middleware('stormpath.produces'); 50 | $this->request = $request; 51 | $this->validator = $validator; 52 | } 53 | 54 | public function getChangePassword() 55 | { 56 | if(!$this->request->has('spToken')) { 57 | return redirect(config('stormpath.web.changePassword.errorUri')); 58 | } 59 | 60 | $token = $this->request->get('spToken'); 61 | if(!$this->isValidToken($token)) { 62 | return redirect(config('stormpath.web.changePassword.errorUri')); 63 | } 64 | 65 | return view(config('stormpath.web.changePassword.view')); 66 | 67 | } 68 | 69 | public function postChangePassword() 70 | { 71 | $newPassword = $this->request->input('password'); 72 | $token = $this->request->input('spToken'); 73 | 74 | $validator = $this->loginValidator(); 75 | 76 | if($validator->fails()) { 77 | 78 | if($this->request->wantsJson()) { 79 | return $this->respondWithError('Validation Failed', 400, ['validatonErrors' => $validator->errors()]); 80 | } 81 | 82 | return redirect() 83 | ->to(config('stormpath.web.changePassword.uri').'?spToken='.$token) 84 | ->withErrors($validator); 85 | } 86 | 87 | $application = app('stormpath.application'); 88 | 89 | try { 90 | $application->resetPassword($token, $newPassword); 91 | 92 | // the password has been changed. Time to fire the 93 | // `UserHasResetPassword` event 94 | // 95 | Event::fire(new UserHasResetPassword); 96 | 97 | if($this->request->wantsJson()) { 98 | return $this->respondOk(); 99 | } 100 | return redirect() 101 | ->to(config('stormpath.web.changePassword.nextUri')); 102 | 103 | } catch (\Stormpath\Resource\ResourceError $re) { 104 | if($this->request->wantsJson()) { 105 | return $this->respondWithError($re->getMessage(), $re->getStatus()); 106 | } 107 | return redirect() 108 | ->to(config('stormpath.web.changePassword.errorUri')) 109 | ->withErrors(['errors'=>[$re->getMessage()]]); 110 | } 111 | } 112 | 113 | private function isValidToken($token) 114 | { 115 | $application = app('stormpath.application'); 116 | try { 117 | $application->verifyPasswordResetToken($token); 118 | return true; 119 | } catch (\Stormpath\Resource\ResourceError $re) { 120 | return false; 121 | } 122 | } 123 | 124 | private function loginValidator() 125 | { 126 | $validator = $this->validator->make( 127 | $this->request->all(), 128 | [ 129 | 'password' => 'required|confirmed' 130 | ], 131 | [ 132 | 'password.required' => 'Password is required.', 133 | 'password.confirmed' => 'Passwords do not match.' 134 | ] 135 | ); 136 | 137 | 138 | return $validator; 139 | } 140 | 141 | private function respondOk() 142 | { 143 | return response()->json(); 144 | } 145 | 146 | private function respondWithError($message, $statusCode = 400, $extra = []) 147 | { 148 | $error = [ 149 | 'errors' => [ 150 | 'message' => $message 151 | ] 152 | ]; 153 | 154 | if(!empty($extra)) { 155 | $error['errors'] = array_merge($error['errors'], $extra); 156 | } 157 | return response()->json($error, $statusCode); 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/Http/Controllers/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('stormpath.produces'); 38 | 39 | $this->request = $request; 40 | } 41 | 42 | public function getForgotPassword() 43 | { 44 | if( config('stormpath.web.idSite.enabled') ) { 45 | return redirect(app('stormpath.application')->createIdSiteUrl(['path'=>config('stormpath.web.idSite.forgotUri'), 'callbackUri'=>route('stormpath.idSiteResponse')])); 46 | } 47 | $status = $this->request->get('status'); 48 | return view( config('stormpath.web.forgotPassword.view'), compact('status') ); 49 | } 50 | 51 | public function postForgotPassword(Request $request) 52 | { 53 | try { 54 | $input = $request->all(); 55 | // we're about to post the "forgot password" request. Fire the 56 | // `UserHasRequestedPasswordReset` event 57 | // 58 | if (false===Event::fire(new UserHasRequestedPasswordReset(['email' => $input['email']]), [], true)) { 59 | throw new ActionAbortedException; 60 | } 61 | 62 | $application = app( 'stormpath.application' ); 63 | $application->sendPasswordResetEmail($input['email']); 64 | 65 | 66 | if($request->wantsJson()) { 67 | return response(null, 200); 68 | } 69 | 70 | return redirect() 71 | ->to(config('stormpath.web.forgotPassword.nextUri')); 72 | 73 | } catch (ResourceError $re) { 74 | 75 | if($request->wantsJson()) { 76 | return response()->json([ 77 | 'message' => 'Could not find an account with this email address', 78 | 'status' => $re->getStatus() 79 | ],400); 80 | }; 81 | 82 | return redirect() 83 | ->to(config('stormpath.web.forgotPassword.uri')) 84 | ->withErrors(['errors'=>['Could not find an account with this email address']]) 85 | ->withInput(); 86 | } 87 | 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Http/Controllers/IdSiteController.php: -------------------------------------------------------------------------------- 1 | handleIdSiteCallback($request->fullUrl()); 33 | 34 | switch ($response->status) { 35 | case 'AUTHENTICATED' : 36 | return $this->authenticate($request); 37 | break; 38 | case 'LOGOUT' : 39 | return $this->logout(); 40 | break; 41 | case 'REGISTERED' : 42 | return redirect(config('stormpath.web.login.uri')); 43 | break; 44 | 45 | } 46 | } catch(\Stormpath\Resource\ResourceError $re) { 47 | throw new IdSiteException('ID Site Exception: ' . $re->getMessage()); 48 | } 49 | } 50 | 51 | private function exchangeIdSiteToken($jwtResponse) 52 | { 53 | $exchangeIdSiteTokenRequest = new \Stormpath\Oauth\ExchangeIdSiteTokenRequest($jwtResponse); 54 | $auth = new \Stormpath\Oauth\ExchangeIdSiteTokenAuthenticator(app('stormpath.application')); 55 | return $auth->authenticate($exchangeIdSiteTokenRequest); 56 | } 57 | 58 | private function authenticate($request) 59 | { 60 | try { 61 | $result = $this->exchangeIdSiteToken($request->query('jwtResponse')); 62 | 63 | return redirect() 64 | ->intended(config('stormpath.web.login.nextUri')) 65 | ->withCookies( 66 | [ 67 | config('stormpath.web.accessTokenCookie.name') => 68 | cookie( 69 | config('stormpath.web.accessTokenCookie.name'), 70 | $result->getAccessTokenString(), 71 | $result->getExpiresIn(), 72 | config('stormpath.web.accessTokenCookie.path'), 73 | config('stormpath.web.accessTokenCookie.domain'), 74 | config('stormpath.web.accessTokenCookie.secure'), 75 | config('stormpath.web.accessTokenCookie.httpOnly') 76 | ), 77 | config('stormpath.web.refreshTokenCookie.name') => 78 | cookie( 79 | config('stormpath.web.refreshTokenCookie.name'), 80 | $result->getRefreshTokenString(), 81 | $result->getExpiresIn(), 82 | config('stormpath.web.refreshTokenCookie.path'), 83 | config('stormpath.web.refreshTokenCookie.domain'), 84 | config('stormpath.web.refreshTokenCookie.secure'), 85 | config('stormpath.web.refreshTokenCookie.httpOnly') 86 | ) 87 | ] 88 | ); 89 | 90 | } catch(\Stormpath\Resource\ResourceError $re) { 91 | throw new IdSiteException('ID Site Exception: ' . $re->getMessage()); 92 | } 93 | } 94 | 95 | private function logout() 96 | { 97 | return redirect() 98 | ->to(config('stormpath.web.logout.nextUri')) 99 | ->withCookies([ 100 | cookie()->forget(config('stormpath.web.accessTokenCookie.name')), 101 | cookie()->forget(config('stormpath.web.refreshTokenCookie.name')) 102 | ]); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Http/Controllers/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('stormpath.produces'); 63 | $this->request = $request; 64 | $this->validator = $validator; 65 | } 66 | 67 | public function getLogin() 68 | { 69 | if( config('stormpath.web.idSite.enabled') ) { 70 | return redirect(app('stormpath.application')->createIdSiteUrl(['callbackUri'=>route('stormpath.idSiteResponse')])); 71 | } 72 | 73 | if($this->request->wantsJson()) { 74 | return $this->respondWithForm(); 75 | } 76 | 77 | $status = $this->request->get('status'); 78 | 79 | return view(config('stormpath.web.login.view'), compact('status')); 80 | 81 | } 82 | 83 | public function postLogin() 84 | { 85 | if($this->isSocialLoginAttempt()) { 86 | return $this->doSocialLogin(); 87 | } 88 | 89 | 90 | $validator = $this->loginValidator(); 91 | 92 | 93 | 94 | if($validator->fails()) { 95 | if($this->request->wantsJson()) { 96 | return $this->respondWithValidationErrorForJson($validator); 97 | } 98 | 99 | return redirect() 100 | ->to(config('stormpath.web.login.uri')) 101 | ->withErrors($validator) 102 | ->withInput(); 103 | } 104 | 105 | try { 106 | // the login request data has passed validation. Time to fire the 107 | // UserIsLoggingIn event 108 | // 109 | if (false===Event::fire(new UserIsLoggingIn(['login'=> $this->request->input('login'), 'password'=> $this->request->input('password')]), [], true)) { 110 | throw new ActionAbortedException; 111 | } 112 | 113 | $result = $this->authenticate($this->request->input('login'), $this->request->input('password')); 114 | $this->queueAccessToken($result->getAccessTokenString()); 115 | $this->queueRefreshToken($result->getRefreshTokenString()); 116 | 117 | $account = $result->getAccessToken()->getAccount(); 118 | 119 | Event::fire(new UserHasLoggedIn($account)); 120 | 121 | if($this->request->wantsJson()) { 122 | return $this->respondWithAccount($account); 123 | } 124 | 125 | 126 | 127 | return redirect() 128 | ->intended(config('stormpath.web.login.nextUri')); 129 | 130 | } catch (\Stormpath\Resource\ResourceError $re) { 131 | 132 | if($this->request->wantsJson()) { 133 | return $this->respondWithError($re->getMessage(), $re->getStatus()); 134 | } 135 | 136 | return redirect() 137 | ->to(config('stormpath.web.login.uri')) 138 | ->withErrors(['errors'=>[$re->getMessage()]]) 139 | ->withInput(); 140 | } 141 | } 142 | 143 | public function getLogout() 144 | { 145 | 146 | if( config('stormpath.web.idSite.enabled') ) { 147 | return redirect(app('stormpath.application')->createIdSiteUrl(['logout'=>true, 'callbackUri'=>route('stormpath.idSiteResponse')])); 148 | } 149 | 150 | if (false===Event::fire(new UserIsLoggingOut, [], true)) { 151 | throw new ActionAbortedException; 152 | } 153 | 154 | if($this->request->wantsJson()) { 155 | return response() 156 | ->json() 157 | ->withCookie( 158 | cookie()->forget(config('stormpath.web.accessTokenCookie.name')) 159 | ) 160 | ->withCookie( 161 | cookie()->forget(config('stormpath.web.refreshTokenCookie.name')) 162 | ); 163 | 164 | // $this->removeTokens($this->request); 165 | 166 | // return response(); 167 | } 168 | 169 | return redirect() 170 | ->to(config('stormpath.web.logout.nextUri')) 171 | ->withCookies([ 172 | cookie()->forget(config('stormpath.web.accessTokenCookie.name')), 173 | cookie()->forget(config('stormpath.web.refreshTokenCookie.name')) 174 | ]); 175 | } 176 | 177 | private function loginValidator() 178 | { 179 | $validator = $this->validator->make( 180 | $this->request->all(), 181 | [ 182 | 'login' => 'required', 183 | 'password' => 'required' 184 | ], 185 | [ 186 | 'login.required' => 'Login is required.', 187 | 'password.required' => 'Password is required.' 188 | ] 189 | ); 190 | 191 | 192 | return $validator; 193 | } 194 | 195 | private function respondWithForm() 196 | { 197 | 198 | $data = [ 199 | 'form' => [ 200 | 'fields' => [ 201 | [ 202 | 'label' => 'Username or Email', 203 | 'name' => 'login', 204 | 'placeholder' => 'Username or Email', 205 | 'required' => true, 206 | 'type' => 'text' 207 | ], 208 | [ 209 | 'label' => 'Password', 210 | 'name' => 'password', 211 | 'placeholder' => 'Password', 212 | 'required' => true, 213 | 'type' => 'password' 214 | ], 215 | [ 216 | 'label' => 'csrf', 217 | 'name' => '_token', 218 | 'placeholder' => '', 219 | 'value' => csrf_token(), 220 | 'required' => true, 221 | 'type' => 'hidden' 222 | ] 223 | ] 224 | ], 225 | 'accountStores' => [ 226 | app('cache.store')->get('stormpath.accountStores') 227 | ], 228 | 229 | ]; 230 | return response()->json($data); 231 | 232 | } 233 | 234 | private function respondWithError($message, $statusCode = 400) 235 | { 236 | $error = [ 237 | 'message' => $message, 238 | 'status' => $statusCode 239 | ]; 240 | return response()->json($error, $statusCode); 241 | } 242 | 243 | private function respondWithAccount(Account $account) 244 | { 245 | $properties = ['account'=>[]]; 246 | $config = config('stormpath.web.me.expand'); 247 | $whiteListResources = []; 248 | foreach($config as $item=>$value) { 249 | if($value == true) { 250 | $whiteListResources[] = $item; 251 | } 252 | } 253 | 254 | $propNames = $account->getPropertyNames(); 255 | foreach($propNames as $prop) { 256 | $property = $this->getPropertyValue($account, $prop); 257 | 258 | if(is_object($property) && !in_array($prop, $whiteListResources)) { 259 | continue; 260 | } 261 | 262 | $properties['account'][$prop] = $property; 263 | } 264 | return response()->json($properties); 265 | } 266 | 267 | private function getPropertyValue($account, $prop) 268 | { 269 | $value = null; 270 | try { 271 | $value = $account->getProperty($prop); 272 | } catch (\Exception $e) {} 273 | 274 | return $value; 275 | 276 | } 277 | 278 | private function isSocialLoginAttempt() 279 | { 280 | $attempt = $this->request->has('providerData'); 281 | 282 | if(!$attempt) { 283 | return false; 284 | } 285 | 286 | switch ($provider = $this->request->input('providerData')['providerId']) 287 | { 288 | /** @codeCoverageIgnoreStart */ 289 | case 'google' : 290 | case 'facebook' : 291 | case 'linkedin' : 292 | return true; 293 | /** @codeCoverageIgnoreEnd */ 294 | case 'stormpath' : 295 | throw new \InvalidArgumentException("Please use the standard login/password method instead"); 296 | default : 297 | throw new \InvalidArgumentException("The social provider {$provider} is not supported"); 298 | } 299 | } 300 | 301 | /** @codeCoverageIgnore */ 302 | private function doSocialLogin() 303 | { 304 | switch ($provider = $this->request->input('providerData')['providerId']) 305 | { 306 | case 'google' : 307 | return app(SocialCallbackController::class)->google($this->request); 308 | case 'facebook' : 309 | return app(SocialCallbackController::class)->facebook($this->request); 310 | case 'linkedin' : 311 | return app(SocialCallbackController::class)->linkedin($this->request); 312 | 313 | } 314 | } 315 | 316 | private function respondWithValidationErrorForJson($validator) 317 | { 318 | 319 | return response()->json([ 320 | 'message' => $validator->errors()->first(), 321 | 'status' => 400 322 | ], 400); 323 | } 324 | 325 | } 326 | -------------------------------------------------------------------------------- /src/Http/Controllers/MeController.php: -------------------------------------------------------------------------------- 1 | cookies->get(config('stormpath.web.accessTokenCookie.name')); 30 | 31 | if($request->headers->has('Authorization')) { 32 | $token = explode(' ', $request->headers->get('Authorization')); 33 | $accessToken = end($token); 34 | } 35 | 36 | try { 37 | $account = $this->getAccountFromAccessToken($accessToken); 38 | return $this->respondWithAccount($account); 39 | } catch (\Exception $e) { 40 | return response('', 401); 41 | } 42 | } 43 | 44 | private function respondWithAccount(Account $account) 45 | { 46 | $properties = ['account'=>[]]; 47 | $config = config('stormpath.web.me.expand'); 48 | $whiteListResources = []; 49 | foreach($config as $item=>$value) { 50 | if($value == true) { 51 | $whiteListResources[] = $item; 52 | } 53 | } 54 | 55 | $propNames = $account->getPropertyNames(); 56 | foreach($propNames as $prop) { 57 | $property = $this->getPropertyValue($account, $prop); 58 | 59 | if(is_object($property) && !in_array($prop, $whiteListResources)) { 60 | continue; 61 | } 62 | 63 | $properties['account'][$prop] = $property; 64 | } 65 | return response()->json($properties); 66 | } 67 | 68 | private function getPropertyValue($account, $prop) 69 | { 70 | $value = null; 71 | try { 72 | $value = $account->getProperty($prop); 73 | } catch (\Exception $e) { 74 | return null; 75 | } 76 | 77 | return $value; 78 | 79 | } 80 | 81 | private function getAccountFromAccessToken($accessToken) 82 | { 83 | \Firebase\JWT\JWT::$leeway = 10; 84 | 85 | $jwt = \Firebase\JWT\JWT::decode($accessToken, config('stormpath.client.apiKey.secret'), ['HS256']); 86 | 87 | $expandsArray = []; 88 | $expands = config('stormpath.web.me.expand'); 89 | foreach($expands as $key=>$value) { 90 | if($value == false) continue; 91 | $expandsArray[] = $key; 92 | } 93 | $toExpand = []; 94 | if(count($expandsArray) > 0) { 95 | $toExpand = ['expand' => implode(',',$expandsArray)]; 96 | } 97 | 98 | $account = \Stormpath\Resource\Account::get($jwt->sub, $toExpand); 99 | return $account; 100 | } 101 | } -------------------------------------------------------------------------------- /src/Http/Controllers/OauthController.php: -------------------------------------------------------------------------------- 1 | getGrantType($request); 32 | 33 | switch($grantType) { 34 | case 'password' : 35 | return $this->doPasswordGrantType($request); 36 | // @codeCoverageIgnoreStart 37 | case 'client_credentials' : 38 | return $this->doClientCredentialsGrantType($request); 39 | // @codeCoverageIgnoreEnd 40 | case 'refresh_token' : 41 | return $this->doRefreshGrantType($request); 42 | default : 43 | return $this->respondUnsupportedGrantType(); 44 | } 45 | 46 | } 47 | 48 | /** @codeCoverageIgnore */ 49 | private function doClientCredentialsGrantType($request) 50 | { 51 | if(!config('stormpath.web.oauth2.client_credentials.enabled')) { 52 | return $this->respondUnsupportedGrantType(); 53 | } 54 | try { 55 | $request = \Stormpath\Authc\Api\Request::createFromGlobals(); 56 | $result = (new OAuthClientCredentialsRequestAuthenticator(app('stormpath.application')))->authenticate($request); 57 | 58 | $tokenResponse = json_decode($result->getAccessToken()); 59 | return response()->json([ 60 | 'access_token' => $tokenResponse->access_token, 61 | 'token_type' => $tokenResponse->token_type, 62 | 'expires_in' => config('stormpath.web.oauth2.client_credentials.accessToken.ttl') 63 | ]); 64 | } catch(\Exception $e) { 65 | return $this->respondWithInvalidRequest($e->getMessage()); 66 | } 67 | } 68 | 69 | private function doPasswordGrantType($request) 70 | { 71 | if(!config('stormpath.web.oauth2.password.enabled')) { 72 | return $this->respondUnsupportedGrantType(); 73 | } 74 | try { 75 | $passwordGrant = new \Stormpath\Oauth\PasswordGrantRequest($request->input('username'), $request->input('password')); 76 | $auth = new \Stormpath\Oauth\PasswordGrantAuthenticator(app('stormpath.application')); 77 | $result = $auth->authenticate($passwordGrant); 78 | return $this->respondWithAccessTokens($result); 79 | } catch (\Exception $e) { 80 | return $this->respondWithInvalidLogin($e); 81 | } 82 | } 83 | 84 | private function respondUnsupportedGrantType() 85 | { 86 | return response()->json([ 87 | 'message' => 'The authorization grant type is not supported by the authorization server.', 88 | 'error' => 'unsupported_grant_type' 89 | ], 400); 90 | } 91 | 92 | private function getGrantType($request) 93 | { 94 | return $request->input('grant_type'); 95 | } 96 | 97 | private function respondWithInvalidLogin($e) 98 | { 99 | return response()->json([ 100 | 'message' => $e->getMessage(), 101 | 'error' => 'invalid_grant' 102 | ], 400); 103 | } 104 | 105 | private function respondWithAccessTokens(OauthGrantAuthenticationResult $result) 106 | { 107 | return response()->json([ 108 | 'access_token' => $result->getAccessTokenString(), 109 | 'expires_in' => $result->getExpiresIn(), 110 | 'refresh_token' => $result->getRefreshTokenString(), 111 | 'token_type' => 'Bearer' 112 | ]); 113 | } 114 | 115 | private function doRefreshGrantType($request) 116 | { 117 | if(null === $request->input('refresh_token')) { 118 | return $this->respondWithInvalidRequest('The refresh_token parameter is required.'); 119 | } 120 | 121 | try { 122 | $refreshGrant = new \Stormpath\Oauth\RefreshGrantRequest($request->input('refresh_token')); 123 | 124 | $auth = new \Stormpath\Oauth\RefreshGrantAuthenticator(app('stormpath.application')); 125 | $result = $auth->authenticate($refreshGrant); 126 | return $this->respondWithAccessTokens($result); 127 | } catch (\Exception $e) { 128 | return $this->respondWithInvalidLogin($e); 129 | } 130 | 131 | } 132 | 133 | private function respondWithInvalidRequest($message = 'Invalid Request') 134 | { 135 | return response()->json([ 136 | 'message' => $message, 137 | 'error' => 'invalid_request' 138 | ], 400); 139 | } 140 | } -------------------------------------------------------------------------------- /src/Http/Controllers/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('stormpath.produces'); 52 | $this->request = $request; 53 | $this->validator = $validator; 54 | } 55 | 56 | public function getRegister() 57 | { 58 | if( config('stormpath.web.idSite.enabled') ) { 59 | return redirect(app('stormpath.application')->createIdSiteUrl(['path'=>config('stormpath.web.idSite.registerUri'), 'callbackUri'=>route('stormpath.idSiteResponse')])); 60 | } 61 | 62 | if($this->request->wantsJson()) { 63 | return $this->respondWithForm(); 64 | } 65 | 66 | $status = $this->request->get('status'); 67 | 68 | return view( config('stormpath.web.register.view'), compact('status') ); 69 | } 70 | 71 | public function postRegister() 72 | { 73 | $validator = $this->registerValidator(); 74 | 75 | if($validator->fails()) { 76 | 77 | if($this->request->wantsJson()) { 78 | return $this->respondWithValidationErrorForJson($validator); 79 | } 80 | 81 | return redirect() 82 | ->to(config('stormpath.web.register.uri')) 83 | ->withErrors($validator) 84 | ->withInput(); 85 | } 86 | 87 | if(($errorFields = $this->isAcceptedPostFields($this->request->all())) !== true) { 88 | return $this->respondWithErrorJson('We do not allow arbitrary data to be posted to an account\'s custom data object. `'. array_shift($errorFields) . '` is either disabled or not defined in the config.', 400); 89 | } 90 | 91 | 92 | try { 93 | $registerFields = $this->setRegisterFields(); 94 | 95 | // the form has passed validation. It's time to fire the 96 | // `UserIsRegistering` event 97 | // 98 | if (false===Event::fire(new UserIsRegistering($registerFields), [], true)) { 99 | throw new ActionAbortedException; 100 | } 101 | 102 | $account = \Stormpath\Resource\Account::instantiate($registerFields); 103 | 104 | app('cache.store')->forget('stormpath.application'); 105 | $application = app('stormpath.application'); 106 | 107 | $account = $application->createAccount($account); 108 | 109 | // the account has been created. Now I need to add any non-standard 110 | // fields from the `$registerFields` array to the 111 | // `$account->customData` object and re-save the account 112 | 113 | // a flag to track whether custom data has been added - if we don't 114 | // add any custom data, we don't need to re-save the account 115 | // 116 | $customDataAdded = false; 117 | 118 | // what follows here is a bit of a kludge. There is no easy way to 119 | // determine which values in the `$registerFields` array are 120 | // "normal" data and which are custom data for an account. This is 121 | // because the `instantiate` method simply sends all the data to the 122 | // server & doesn't check to see which values are used and which are 123 | // not. So in the loop below, I am checking each item in the 124 | // `$registerFields` array - if it exists as a property on the 125 | // `$account` object, then it doesn't need to be added as a custom 126 | // data value. 127 | // 128 | foreach ($registerFields as $key=>$value) { 129 | // make sure we're not adding the password or passwordConfirm 130 | // fields 131 | // 132 | if ($key!='password' && $key!='confirmPassword') { 133 | if ($account->{$key}!=$registerFields[$key]) { 134 | $account->customData->{$key} = $value; 135 | $customDataAdded = true; 136 | } 137 | } 138 | } 139 | 140 | // was any custom data added? if so, save the account object 141 | // 142 | if ($customDataAdded) { 143 | $account->save(); 144 | } 145 | 146 | // the account has been created. Time to fire the 147 | // `UserHasRegistered` event. 148 | // 149 | Event::fire(new UserHasRegistered($account)); 150 | if($this->request->wantsJson()) { 151 | return $this->respondWithAccount($account); 152 | } 153 | 154 | if(config('stormpath.web.verifyEmail.enabled') == true) { 155 | return redirect() 156 | ->route('stormpath.login', ['status'=>'unverified']); 157 | } 158 | 159 | if(config('stormpath.web.register.autoAuthorize') == false) { 160 | return redirect() 161 | ->route('stormpath.login', ['status'=>'created']); 162 | } 163 | 164 | $login = isset($registerFields['username']) ? $registerFields['username'] : null; 165 | $login = isset($registerFields['email']) ? $registerFields['email'] : $login; 166 | 167 | $result = $this->authenticate($login, $registerFields['password']); 168 | $this->queueAccessToken($result->getAccessTokenString()); 169 | $this->queueRefreshToken($result->getRefreshTokenString()); 170 | 171 | 172 | return redirect() 173 | ->to(config('stormpath.web.register.nextUri')); 174 | 175 | 176 | } catch(\Stormpath\Resource\ResourceError $re) { 177 | if($this->request->wantsJson()) { 178 | return $this->respondWithErrorJson($re->getMessage(), $re->getStatus()); 179 | } 180 | return redirect() 181 | ->to(config('stormpath.web.register.uri')) 182 | ->withErrors(['errors'=>[$re->getMessage()]]) 183 | ->withInput(); 184 | } 185 | 186 | } 187 | 188 | private function registerValidator() 189 | { 190 | $rules = []; 191 | $messages = []; 192 | $input = $this->request->all(); 193 | 194 | $registerField = config('stormpath.web.register.form.fields'); 195 | 196 | foreach($registerField as $key => $field) { 197 | if($field['enabled'] == true && $field['required'] == true) { 198 | $rules[$key] = 'required'; 199 | } 200 | } 201 | 202 | $messages['username.required'] = 'Username is required.'; 203 | $messages['givenName.required'] = 'Given name is required.'; 204 | $messages['middleName.required'] = 'Middle name is required.'; 205 | $messages['surname.required'] = 'Surname is required.'; 206 | $messages['email.required'] = 'Email is required.'; 207 | $messages['password.required'] = 'Password is required.'; 208 | $messages['confirmPassword.required'] = 'Password confirmation is required.'; 209 | 210 | 211 | if( config('stormpath.web.register.form.fields.confirmPassword.enabled') ) { 212 | $rules['password'] = 'required|same:confirmPassword'; 213 | $messages['password.same'] = 'Passwords are not the same.'; 214 | } 215 | 216 | $validator = $this->validator->make( 217 | $this->request->all(), 218 | $rules, 219 | $messages 220 | ); 221 | 222 | 223 | return $validator; 224 | } 225 | 226 | private function setRegisterFields() 227 | { 228 | $registerArray = []; 229 | $registerFields = config('stormpath.web.register.form.fields'); 230 | foreach($registerFields as $spfield=>$field) { 231 | if($field['required'] == true) { 232 | $registerArray[$spfield] = $this->request->input($spfield); 233 | } 234 | } 235 | 236 | return $registerArray; 237 | } 238 | 239 | private function respondWithForm() 240 | { 241 | $fields = []; 242 | $fields[] = [ 243 | 'label' => 'csrf', 244 | 'name' => '_token', 245 | 'placeholder' => '', 246 | 'value' => csrf_token(), 247 | 'required' => true, 248 | 'type' => 'hidden' 249 | ]; 250 | foreach(config('stormpath.web.register.form.fields') as $field) { 251 | if($field['enabled'] == true) { 252 | $fields[] = $field; 253 | } 254 | } 255 | 256 | $data = [ 257 | 'form' => [ 258 | 'fields' => $fields 259 | ], 260 | 'accountStores' => [ 261 | app('cache.store')->get('stormpath.accountStores') 262 | ] 263 | ]; 264 | 265 | return response()->json($data); 266 | } 267 | 268 | 269 | private function respondWithErrorJson($message, $statusCode = 400) 270 | { 271 | $error = [ 272 | 'message' => $message, 273 | 'status' => $statusCode 274 | ]; 275 | 276 | return response()->json($error, $statusCode); 277 | } 278 | 279 | 280 | private function respondWithAccount(Account $account) 281 | { 282 | $properties = ['account'=>[]]; 283 | $config = config('stormpath.web.me.expand'); 284 | $whiteListResources = []; 285 | foreach($config as $item=>$value) { 286 | if($value == true) { 287 | $whiteListResources[] = $item; 288 | } 289 | } 290 | 291 | $propNames = $account->getPropertyNames(); 292 | foreach($propNames as $prop) { 293 | $property = $this->getPropertyValue($account, $prop); 294 | 295 | if(is_object($property) && !in_array($prop, $whiteListResources)) { 296 | continue; 297 | } 298 | 299 | $properties['account'][$prop] = $property; 300 | } 301 | return response()->json($properties); 302 | } 303 | 304 | private function getPropertyValue($account, $prop) 305 | { 306 | $value = null; 307 | try { 308 | $value = $account->getProperty($prop); 309 | } catch (\Exception $e) {} 310 | 311 | return $value; 312 | 313 | } 314 | 315 | private function respondWithValidationErrorForJson($validator) 316 | { 317 | 318 | return response()->json([ 319 | 'message' => $validator->errors()->first(), 320 | 'status' => 400 321 | ], 400); 322 | } 323 | 324 | private function isAcceptedPostFields($submittedFields) 325 | { 326 | $fields = []; 327 | $allowedFields = config('stormpath.web.register.form.fields'); 328 | 329 | foreach($allowedFields as $key => $value) { 330 | //Enabled check when iOS SDK is updated to not use username in tests 331 | // if($value['enabled'] == false) continue; 332 | $fields[] = $key; 333 | } 334 | $fields[] = '_token'; 335 | 336 | if(!empty($diff = array_diff(array_keys($submittedFields), array_values($fields)))) { 337 | return $diff; 338 | } 339 | 340 | return true; 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /src/Http/Controllers/SocialCallbackController.php: -------------------------------------------------------------------------------- 1 | application = $application; 44 | 45 | app('cache.store')->forget('stormpath.application'); 46 | 47 | if(null === $this->application) { 48 | $this->application = app('stormpath.application'); 49 | } 50 | 51 | } 52 | 53 | public function facebook(Request $request) 54 | { 55 | try { 56 | 57 | $providerAccountRequest = new FacebookProviderAccountRequest($this->buildProviderAccountRequestArray($request)); 58 | 59 | $account = $this->sendProviderAccountRequest($providerAccountRequest); 60 | 61 | $this->setCookies($account); 62 | 63 | if(app('request')->wantsJson()) { 64 | return $this->respondWithAccount($account); 65 | } 66 | 67 | return redirect() 68 | ->intended(config('stormpath.web.login.nextUri')); 69 | 70 | } catch (\Stormpath\Resource\ResourceError $re) { 71 | if(app('request')->wantsJson()) { 72 | return $this->respondWithError($re); 73 | } 74 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$re->getMessage()]]); 75 | } catch (SocialLoginException $e) { 76 | if(app('request')->wantsJson()) { 77 | return $this->respondWithError($e); 78 | } 79 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$e->getMessage()]]); 80 | } 81 | 82 | } 83 | 84 | public function google(Request $request) 85 | { 86 | try { 87 | $providerAccountRequest = new \Stormpath\Provider\GoogleProviderAccountRequest($this->buildProviderAccountRequestArray($request)); 88 | 89 | $account = $this->sendProviderAccountRequest($providerAccountRequest); 90 | 91 | $this->setCookies($account); 92 | 93 | if(app('request')->wantsJson()) { 94 | return $this->respondWithAccount($account); 95 | } 96 | 97 | 98 | return redirect()->to(config('stormpath.web.login.nextUri')); 99 | } catch (\Stormpath\Resource\ResourceError $re) { 100 | if(app('request')->wantsJson()) { 101 | return $this->respondWithError($re); 102 | } 103 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$re->getMessage()]]); 104 | } catch (SocialLoginException $e) { 105 | if(app('request')->wantsJson()) { 106 | return $this->respondWithError($e); 107 | } 108 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$e->getMessage()]]); 109 | } 110 | 111 | } 112 | 113 | public function github(Request $request) 114 | { 115 | try { 116 | 117 | $providerAccountRequest = new GithubProviderAccountRequest($this->buildProviderAccountRequestArray($request)); 118 | 119 | $account = $this->sendProviderAccountRequest($providerAccountRequest); 120 | 121 | $this->setCookies($account); 122 | 123 | if(app('request')->wantsJson()) { 124 | return $this->respondWithAccount($account); 125 | } 126 | 127 | return redirect() 128 | ->intended(config('stormpath.web.login.nextUri')); 129 | 130 | } catch (\Stormpath\Resource\ResourceError $re) { 131 | if(app('request')->wantsJson()) { 132 | return $this->respondWithError($re); 133 | } 134 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$re->getMessage()]]); 135 | } catch (SocialLoginException $e) { 136 | if(app('request')->wantsJson()) { 137 | return $this->respondWithError($e); 138 | } 139 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$e->getMessage()]]); 140 | } 141 | 142 | } 143 | 144 | public function linkedin(Request $request) 145 | { 146 | if($request->has('error')) { 147 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$request->get('error_description')]]); 148 | } 149 | try { 150 | 151 | $providerAccountRequest = new LinkedInProviderAccountRequest($this->buildProviderAccountRequestArray($request)); 152 | 153 | $account = $this->sendProviderAccountRequest($providerAccountRequest); 154 | 155 | $this->setCookies($account); 156 | 157 | if(app('request')->wantsJson()) { 158 | return $this->respondWithAccount($account); 159 | } 160 | 161 | return redirect() 162 | ->intended(config('stormpath.web.login.nextUri')); 163 | 164 | } catch (\Stormpath\Resource\ResourceError $re) { 165 | if(app('request')->wantsJson()) { 166 | return $this->respondWithError($re); 167 | } 168 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$re->getMessage()]]); 169 | } catch (SocialLoginException $e) { 170 | if(app('request')->wantsJson()) { 171 | return $this->respondWithError($e); 172 | } 173 | return redirect()->to(config('stormpath.web.login.uri'))->withErrors(['errors'=>[$e->getMessage()]]); 174 | } 175 | 176 | } 177 | 178 | 179 | protected function sendProviderAccountRequest(ProviderAccountRequest $providerAccountRequest) 180 | { 181 | $result = $this->application->getAccount($providerAccountRequest); 182 | return $result->account; 183 | } 184 | 185 | protected function setCookies(Account $account) 186 | { 187 | $idSiteSession = new IdSiteSessionHelper(); 188 | $accessTokens = $idSiteSession->create($account); 189 | 190 | $this->queueAccessToken($accessTokens->getProperty('access_token')); 191 | $this->queueRefreshToken($accessTokens->getProperty('refresh_token')); 192 | 193 | } 194 | 195 | private function respondWithAccount(Account $account) 196 | { 197 | $properties = ['account'=>[]]; 198 | $config = config('stormpath.web.me.expand'); 199 | $whiteListResources = []; 200 | foreach($config as $item=>$value) { 201 | if($value == true) { 202 | $whiteListResources[] = $item; 203 | } 204 | } 205 | 206 | $propNames = $account->getPropertyNames(); 207 | foreach($propNames as $prop) { 208 | $property = $this->getPropertyValue($account, $prop); 209 | 210 | if(is_object($property) && !in_array($prop, $whiteListResources)) { 211 | continue; 212 | } 213 | 214 | $properties['account'][$prop] = $property; 215 | } 216 | return response()->json($properties); 217 | } 218 | 219 | private function getPropertyValue($account, $prop) 220 | { 221 | $value = null; 222 | try { 223 | $value = $account->getProperty($prop); 224 | } catch (\Exception $e) { 225 | return null; 226 | } 227 | 228 | return $value; 229 | 230 | } 231 | 232 | private function respondWithError($exception) 233 | { 234 | return response()->json([ 235 | 'message' => $exception->getMessage(), 236 | 'status' => $exception->getStatus() 237 | ], $exception->getStatus()); 238 | } 239 | 240 | private function buildProviderAccountRequestArray($request) 241 | { 242 | $array = []; 243 | 244 | if($request->has('code')) { 245 | $array['code'] = $request->get('code'); 246 | } 247 | 248 | if($request->has('access_token')) { 249 | $array['accessToken'] = $request->get('access_token'); 250 | } 251 | 252 | if($request->has('providerData')) { 253 | if(!empty($request->get('providerData')['accessToken'])) { 254 | $array['accessToken'] = $request->get('providerData')['accessToken']; 255 | } 256 | } 257 | 258 | return $array; 259 | } 260 | 261 | } 262 | -------------------------------------------------------------------------------- /src/Http/Helpers/IdSiteModel.php: -------------------------------------------------------------------------------- 1 | setProperty('token', $token); 26 | return $this; 27 | } 28 | 29 | public function setGrantType($type) 30 | { 31 | $this->setProperty('grant_type', $type); 32 | return $this; 33 | } 34 | 35 | public function getStormpathToken() 36 | { 37 | return $this->getProperty('token'); 38 | } 39 | 40 | public function getGrantType() 41 | { 42 | return $this->getProperty('grant_type'); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Http/Helpers/IdSiteSessionHelper.php: -------------------------------------------------------------------------------- 1 | $account->href, 33 | 'iat' => time()-1, 34 | 'status' => 'AUTHENTICATED', 35 | 'iss' => $application->href, 36 | 'aud' => config('stormpath.client.apiKey.id') 37 | ], config('stormpath.client.apiKey.secret'), 'HS256'); 38 | 39 | $idSiteRequest = new IdSiteRequest(); 40 | $idSiteRequest->stormpathToken = $jwt; 41 | $idSiteRequest->grantType = 'stormpath_token'; 42 | 43 | return app('stormpath.client')->getDataStore()->create($application->href . '/oauth/token', $idSiteRequest, Stormpath::ACCESS_TOKEN); 44 | 45 | 46 | } catch (\Exception $e) { 47 | throw new SocialLoginException($e->getMessage()); 48 | } 49 | 50 | } 51 | 52 | 53 | 54 | } -------------------------------------------------------------------------------- /src/Http/Helpers/PasswordPolicies.php: -------------------------------------------------------------------------------- 1 | cookieJar = $cookieJar; 32 | } 33 | 34 | /** 35 | * Handle an incoming request to make sure a user is authenticated to allow them to view the route 36 | * 37 | * @param \Illuminate\Http\Request $request 38 | * @param \Closure $next 39 | * @return mixed 40 | */ 41 | public function handle(Request $request, Closure $next) 42 | { 43 | if ($this->isAuthenticated($request)) { 44 | return $next($request); 45 | } 46 | 47 | if ($this->refreshTokens($request)) { 48 | return $next($request); 49 | } 50 | 51 | return $this->responseUnauthenticated($request); 52 | 53 | } 54 | 55 | public function isAuthenticated(Request $request) 56 | { 57 | $token = $request->bearerToken(); 58 | 59 | if(null === $token) { 60 | $token = $request->cookie(config('stormpath.web.accessTokenCookie.name')); 61 | } 62 | 63 | if($token instanceof \Symfony\Component\HttpFoundation\Cookie) { 64 | $token = $token->getValue(); 65 | } 66 | 67 | try { 68 | (new \Stormpath\Oauth\VerifyAccessToken(app('stormpath.application')))->verify($token); 69 | return true; 70 | } catch (\Exception $re) { 71 | return false; 72 | } 73 | } 74 | 75 | public function refreshTokens(Request $request) { 76 | if ($request->wantsJson()) { 77 | return false; 78 | } 79 | 80 | try { 81 | $spApplication = app('stormpath.application'); 82 | } catch (\Exception $e) { 83 | return false; 84 | } 85 | 86 | $cookie = $request->cookie(config('stormpath.web.refreshTokenCookie.name')); 87 | if($cookie instanceof \Symfony\Component\HttpFoundation\Cookie) 88 | $cookie = $cookie->getValue(); 89 | 90 | try { 91 | $refreshGrant = new \Stormpath\Oauth\RefreshGrantRequest($cookie); 92 | $auth = new \Stormpath\Oauth\RefreshGrantAuthenticator($spApplication); 93 | $result = $auth->authenticate($refreshGrant); 94 | 95 | $this->setNewAccessToken($request, $result); 96 | 97 | return true; 98 | 99 | } catch(\Stormpath\Resource\ResourceError $re) { 100 | return false; 101 | } 102 | 103 | } 104 | 105 | private function responseUnauthenticated(Request $request) 106 | { 107 | if ($request->wantsJson()) { 108 | return response(null, 401); 109 | } 110 | 111 | return redirect()->route('stormpath.login'); 112 | } 113 | 114 | private function setNewAccessToken($request, $cookies) 115 | { 116 | $this->cookieJar->queue( 117 | cookie( 118 | config('stormpath.web.accessTokenCookie.name'), 119 | $cookies->getAccessTokenString(), 120 | $cookies->getExpiresIn(), 121 | config('stormpath.web.accessTokenCookie.path'), 122 | config('stormpath.web.accessTokenCookie.domain'), 123 | config('stormpath.web.accessTokenCookie.secure'), 124 | config('stormpath.web.accessTokenCookie.httpOnly') 125 | ) 126 | 127 | ); 128 | 129 | 130 | $request->cookies->add([config('stormpath.web.accessTokenCookie.name') => $cookies->getAccessTokenString() ]); 131 | 132 | } 133 | 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/Http/Middleware/Produces.php: -------------------------------------------------------------------------------- 1 | produces = config('stormpath.web.produces'); 49 | $acceptHeader = explode(',',$request->header('Accept')); 50 | $approvedProduces = array_intersect($this->systemProduces, $this->produces); 51 | 52 | if(!$this->hasApprovedProduces($approvedProduces)) { 53 | return $this->respondNotAcceptable('The system does not know how to respond to any accept headers defined.'); 54 | } 55 | 56 | if(in_array('*/*', $acceptHeader)) { 57 | $request->headers->remove('Accept'); 58 | $request->headers->set('Accept', $this->produces[0]); 59 | return $next($request); 60 | } 61 | 62 | if(!$this->acceptHeaderIsApproved($acceptHeader, $approvedProduces)) { 63 | return $this->respondNotAcceptable('Accept Header is not allowed.'); 64 | } 65 | 66 | return $next($request); 67 | } 68 | 69 | private function respondNotAcceptable($message) 70 | { 71 | return response($message, 406); 72 | } 73 | 74 | /** 75 | * @param $approvedProduces 76 | * @return bool 77 | */ 78 | private function hasApprovedProduces($approvedProduces) 79 | { 80 | return !! count($approvedProduces); 81 | } 82 | 83 | /** 84 | * @param $acceptHeader 85 | * @param $approvedProduces 86 | * @return int 87 | */ 88 | private function acceptHeaderIsApproved($acceptHeader, $approvedProduces) 89 | { 90 | return !! count(array_intersect((array)$acceptHeader, $approvedProduces)); 91 | } 92 | 93 | 94 | } -------------------------------------------------------------------------------- /src/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | cookieJar = $cookieJar; 31 | } 32 | 33 | /** 34 | * Handle an incoming request. 35 | * 36 | * @param \Illuminate\Http\Request $request 37 | * @param \Closure $next 38 | * @return mixed 39 | */ 40 | public function handle($request, Closure $next) 41 | { 42 | if ($this->isAuthenticated($request)) { 43 | return redirect()->intended('/'); 44 | } 45 | 46 | if($request->wantsJson()) { 47 | return response(null, 401); 48 | } 49 | 50 | $accessToken = $this->refreshCookie($request); 51 | 52 | if (null !== $accessToken) { 53 | return redirect()->intended('/'); 54 | } 55 | 56 | return $next($request); 57 | } 58 | 59 | 60 | public function isAuthenticated($request) 61 | { 62 | $cookie = $request->cookie(config('stormpath.web.accessTokenCookie.name')); 63 | 64 | if(null === $cookie) { 65 | return false; 66 | } 67 | 68 | if($cookie instanceof \Symfony\Component\HttpFoundation\Cookie) { 69 | $cookie = $cookie->getValue(); 70 | } 71 | 72 | try { 73 | (new \Stormpath\Oauth\VerifyAccessToken(app('stormpath.application')))->verify($cookie); 74 | return true; 75 | } catch (\Exception $re) { 76 | return false; 77 | } 78 | } 79 | 80 | private function refreshCookie($request) 81 | { 82 | try { 83 | $spApplication = app('stormpath.application'); 84 | } catch (\Exception $e) { 85 | return null; 86 | } 87 | 88 | $cookie = $request->cookie(config('stormpath.web.refreshTokenCookie.name')); 89 | if($cookie instanceof \Symfony\Component\HttpFoundation\Cookie) 90 | $cookie = $cookie->getValue(); 91 | 92 | try { 93 | $refreshGrant = new \Stormpath\Oauth\RefreshGrantRequest($cookie); 94 | $auth = new \Stormpath\Oauth\RefreshGrantAuthenticator($spApplication); 95 | $result = $auth->authenticate($refreshGrant); 96 | 97 | $this->setNewAccessToken($request, $result); 98 | 99 | return $result->getAccessTokenString(); 100 | 101 | } catch(\Stormpath\Resource\ResourceError $re) { 102 | return null; 103 | } 104 | } 105 | 106 | private function setNewAccessToken($request, $cookies) 107 | { 108 | $this->cookieJar->queue( 109 | cookie( 110 | config('stormpath.web.accessTokenCookie.name'), 111 | $cookies->getAccessTokenString(), 112 | $cookies->getExpiresIn(), 113 | config('stormpath.web.accessTokenCookie.path'), 114 | config('stormpath.web.accessTokenCookie.domain'), 115 | config('stormpath.web.accessTokenCookie.secure'), 116 | config('stormpath.web.accessTokenCookie.httpOnly') 117 | ) 118 | 119 | ); 120 | 121 | 122 | $request->cookies->add([config('stormpath.web.accessTokenCookie.name') => $cookies->getAccessTokenString() ]); 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Http/Traits/AuthenticatesUser.php: -------------------------------------------------------------------------------- 1 | authenticate($passwordGrant); 27 | } 28 | } -------------------------------------------------------------------------------- /src/Http/Traits/Cookies.php: -------------------------------------------------------------------------------- 1 | makeAccessTokenCookie($accessToken); 27 | 28 | $cookieJar->queue($cookie); 29 | } 30 | 31 | public function makeAccessTokenCookie($accessToken) 32 | { 33 | return cookie( 34 | config('stormpath.web.accessTokenCookie.name'), 35 | $accessToken, 36 | $this->getExpiresTime('accessToken') / 60, 37 | config('stormpath.web.accessTokenCookie.path'), 38 | config('stormpath.web.accessTokenCookie.domain'), 39 | config('stormpath.web.accessTokenCookie.secure'), 40 | config('stormpath.web.accessTokenCookie.httpOnly') 41 | ); 42 | } 43 | 44 | public function queueRefreshToken($refreshToken) 45 | { 46 | $cookieJar = app('cookie'); 47 | 48 | $cookie = $this->makeRefreshTokenCookie($refreshToken); 49 | 50 | $cookieJar->queue($cookie); 51 | } 52 | 53 | public function makeRefreshTokenCookie($refreshToken) 54 | { 55 | return cookie( 56 | config('stormpath.web.refreshTokenCookie.name'), 57 | $refreshToken, 58 | $this->getExpiresTime('refreshToken') / 60, 59 | config('stormpath.web.refreshTokenCookie.path'), 60 | config('stormpath.web.refreshTokenCookie.domain'), 61 | config('stormpath.web.refreshTokenCookie.secure'), 62 | config('stormpath.web.refreshTokenCookie.httpOnly') 63 | ); 64 | } 65 | 66 | private function getExpiresTime($type = 'accessToken') 67 | { 68 | $application = app('stormpath.application'); 69 | 70 | $policy = $application->oauthPolicy; 71 | $methodName = 'get' . ucfirst($type) . 'Ttl'; 72 | 73 | $policy->setOptions([]); 74 | 75 | $time = $policy->{$methodName}(['expand'=>'tokenEndpoint']); 76 | 77 | $converter = new \Bretterer\IsoDurationConverter\DurationParser(); 78 | 79 | $seconds = $converter->parse($time); 80 | 81 | return $seconds; 82 | 83 | } 84 | } -------------------------------------------------------------------------------- /src/Http/routes.php: -------------------------------------------------------------------------------- 1 | =")) { 34 | $middleware = ['middleware' => ['web']]; 35 | } 36 | 37 | $this->app->router->group($middleware, function() { 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Login Routes 41 | |-------------------------------------------------------------------------- 42 | */ 43 | if (config('stormpath.web.login.enabled')) { 44 | $this->app->router->get(config('stormpath.web.login.uri'), ['as' => 'stormpath.login', 'uses' => 'Stormpath\Laravel\Http\Controllers\LoginController@getLogin']); 45 | $this->app->router->post(config('stormpath.web.login.uri'), ['as' => 'stormpath.login', 'uses' => 'Stormpath\Laravel\Http\Controllers\LoginController@postLogin']); 46 | } 47 | 48 | /* 49 | |-------------------------------------------------------------------------- 50 | | Logout Routes 51 | |-------------------------------------------------------------------------- 52 | */ 53 | if (config('stormpath.web.logout.enabled')) { 54 | $this->app->router->post(config('stormpath.web.logout.uri'), ['as' => 'stormpath.logout', 'uses' => 'Stormpath\Laravel\Http\Controllers\LoginController@getLogout']); 55 | } 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Register Routes 60 | |-------------------------------------------------------------------------- 61 | */ 62 | if (config('stormpath.web.register.enabled')) { 63 | $this->app->router->get(config('stormpath.web.register.uri'), ['as' => 'stormpath.register', 'uses' => 'Stormpath\Laravel\Http\Controllers\RegisterController@getRegister']); 64 | $this->app->router->post(config('stormpath.web.register.uri'), ['as' => 'stormpath.register', 'uses' => 'Stormpath\Laravel\Http\Controllers\RegisterController@postRegister']); 65 | } 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | Forgot Password Routes 70 | |-------------------------------------------------------------------------- 71 | */ 72 | if (config('stormpath.web.forgotPassword.enabled')) { 73 | $this->app->router->get(config('stormpath.web.forgotPassword.uri'), ['as' => 'stormpath.forgotPassword', 'uses' => 'Stormpath\Laravel\Http\Controllers\ForgotPasswordController@getForgotPassword']); 74 | $this->app->router->post(config('stormpath.web.forgotPassword.uri'), ['as' => 'stormpath.forgotPassword', 'uses' => 'Stormpath\Laravel\Http\Controllers\ForgotPasswordController@postForgotPassword']); 75 | } 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Change Password Routes 80 | |-------------------------------------------------------------------------- 81 | */ 82 | if (config('stormpath.web.changePassword.enabled')) { 83 | $this->app->router->get(config('stormpath.web.changePassword.uri'), ['as' => 'stormpath.changePassword', 'uses' => 'Stormpath\Laravel\Http\Controllers\ChangePasswordController@getChangePassword']); 84 | $this->app->router->post(config('stormpath.web.changePassword.uri'), ['as' => 'stormpath.changePassword', 'uses' => 'Stormpath\Laravel\Http\Controllers\ChangePasswordController@postChangePassword']); 85 | } 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | ID Site Response Route 90 | |-------------------------------------------------------------------------- 91 | */ 92 | if (config('stormpath.web.idSite.enabled')) { 93 | $this->app->router->get(config('stormpath.web.idSite.uri'), ['as' => 'stormpath.idSiteResponse', 'uses' => 'Stormpath\Laravel\Http\Controllers\IdSiteController@response']); 94 | } 95 | 96 | /* 97 | |-------------------------------------------------------------------------- 98 | | Oauth Routes 99 | |-------------------------------------------------------------------------- 100 | */ 101 | if (config('stormpath.web.oauth2.enabled')) { 102 | $this->app->router->post(config('stormpath.web.oauth2.uri'), ['as' => 'stormpath.oauth.token', 'uses' => 'Stormpath\Laravel\Http\Controllers\OauthController@getTokens']); 103 | } 104 | 105 | /* 106 | |-------------------------------------------------------------------------- 107 | | Me Routes 108 | |-------------------------------------------------------------------------- 109 | */ 110 | if (config('stormpath.web.me.enabled')) { 111 | $this->app->router->get(config('stormpath.web.me.uri'), ['as' => 'stormpath.me', 'uses' => 'Stormpath\Laravel\Http\Controllers\MeController@getMe']); 112 | } 113 | 114 | }); 115 | -------------------------------------------------------------------------------- /src/Http/socialRoutes.php: -------------------------------------------------------------------------------- 1 | =")) { 22 | $middleware = ['middleware' => ['web']]; 23 | } 24 | 25 | $this->app->router->group($middleware, function() { 26 | // /* 27 | // |-------------------------------------------------------------------------- 28 | // | Social Provider Routes 29 | // |-------------------------------------------------------------------------- 30 | // */ 31 | // if (config('stormpath.web.social.enabled')) { 32 | // $this->app->router->get(config('stormpath.web.login.uri') . '/facebook', ['as' => 'stormpath.login.facebook', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialController@facebook']); 33 | // $this->app->router->get(config('stormpath.web.login.uri') . '/google', ['as' => 'stormpath.login.google', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialController@google']); 34 | // $this->app->router->get(config('stormpath.web.login.uri') . '/linkedin', ['as' => 'stormpath.login.linkedin', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialController@linkedin']); 35 | // } 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Social Callback Routes 40 | |-------------------------------------------------------------------------- 41 | */ 42 | if (config('stormpath.web.social.enabled')) { 43 | if (config('stormpath.web.social.facebook.enabled')) { 44 | $this->app->router->get(config('stormpath.web.social.facebook.uri'), ['as' => 'stormpath.callbacks.facebook', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialCallbackController@facebook']); 45 | } 46 | 47 | if (config('stormpath.web.social.google.enabled')) { 48 | $this->app->router->get(config('stormpath.web.social.google.uri'), ['as' => 'stormpath.callbacks.google', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialCallbackController@google']); 49 | } 50 | 51 | if (config('stormpath.web.social.github.enabled')) { 52 | $this->app->router->get(config('stormpath.web.social.github.uri'), ['as' => 'stormpath.callbacks.github', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialCallbackController@github']); 53 | } 54 | 55 | if (config('stormpath.web.social.linkedin.enabled')) { 56 | $this->app->router->get(config('stormpath.web.social.linkedin.uri'), ['as' => 'stormpath.callbacks.linkedin', 'uses' => 'Stormpath\Laravel\Http\Controllers\SocialCallbackController@linkedin']); 57 | } 58 | 59 | } 60 | }); -------------------------------------------------------------------------------- /src/Support/StormpathLaravelServiceProvider.php: -------------------------------------------------------------------------------- 1 | app['router']->middleware('stormpath.auth', \Stormpath\Laravel\Http\Middleware\Authenticate::class); 46 | $this->app['router']->middleware('stormpath.guest', \Stormpath\Laravel\Http\Middleware\RedirectIfAuthenticated::class); 47 | $this->app['router']->middleware('stormpath.produces', \Stormpath\Laravel\Http\Middleware\Produces::class); 48 | $this->registerConfig(); 49 | $this->registerClient(); 50 | $this->registerApplication(); 51 | 52 | $this->registerUser(); 53 | 54 | $this->app->resolving(EncryptCookies::class, function ($object) { 55 | $object->disableFor(config('stormpath.web.accessTokenCookie.name')); 56 | $object->disableFor(config('stormpath.web.refreshTokenCookie.name')); 57 | }); 58 | 59 | } 60 | 61 | /** 62 | * Perform post-registration booting of services. 63 | * 64 | * @return void 65 | */ 66 | public function boot() 67 | { 68 | 69 | $this->warmResources(); 70 | 71 | $this->checkForSocialProviders(); 72 | $this->setPasswordPolicies(); 73 | $this->setAccountCreationPolicy(); 74 | 75 | $this->loadViewsFrom(__DIR__.'/../views', 'stormpath'); 76 | $this->loadRoutes(); 77 | 78 | 79 | 80 | 81 | } 82 | 83 | public function provides() 84 | { 85 | return [ 86 | 'stormpath.client', 87 | 'stormpath.application' 88 | ]; 89 | } 90 | 91 | private function warmResources() 92 | { 93 | if(config('stormpath.application.href') == null) return; 94 | $cache = $this->app['cache.store']; 95 | 96 | 97 | if($cache->has('stormpath.resourcesWarm') && $cache->get('stormpath.resourcesWarm') == true) return; 98 | 99 | app('stormpath.client'); 100 | $application = app('stormpath.application'); 101 | 102 | $dasm = AccountStoreMapping::get($application->defaultAccountStoreMapping->href); 103 | 104 | $mappings = $application->getAccountStoreMappings(['expand'=>'accountStore']); 105 | $accountStoreArray = []; 106 | 107 | foreach($mappings as $mapping) { 108 | $accountStoreArrayValues = [ 109 | 'href' => $mapping->accountStore->href, 110 | 'name' => $mapping->accountStore->name 111 | ]; 112 | 113 | if(isset($mapping->accountStore->provider)) { 114 | $accountStoreArrayValues['provider'] = [ 115 | 'href' => $mapping->accountStore->provider->href, 116 | 'providerId' => $mapping->accountStore->provider->providerId 117 | ]; 118 | } 119 | 120 | $accountStoreArray[] = $accountStoreArrayValues; 121 | } 122 | 123 | 124 | $asm = AccountStoreMapping::get($application->accountStoreMappings->href,['expand'=>'accountStore']); 125 | 126 | $passwordPolicy = $dasm->getAccountStore()->getProperty('passwordPolicy'); 127 | 128 | $accountCreationPolicy = $dasm->getAccountStore(['expand'=>'accountCreationPolicy'])->accountCreationPolicy; 129 | 130 | $passwordPolicies = PasswordPolicies::get($passwordPolicy->href); 131 | 132 | 133 | $cache->rememberForever('stormpath.defaultAccountStoreMapping', function() use ($dasm) { 134 | return $dasm; 135 | }); 136 | 137 | $cache->rememberForever('stormpath.accountStoreMappings', function() use ($asm) { 138 | return $asm; 139 | }); 140 | 141 | $cache->rememberForever('stormpath.accountStores', function() use ($accountStoreArray) { 142 | return $accountStoreArray; 143 | }); 144 | 145 | $cache->rememberForever('stormpath.passwordPolicy', function() use ($passwordPolicy) { 146 | return $passwordPolicy; 147 | }); 148 | 149 | $cache->rememberForever('stormpath.accountCreationPolicy', function() use ($accountCreationPolicy) { 150 | return $accountCreationPolicy; 151 | }); 152 | 153 | $cache->rememberForever('stormpath.passwordPolicies', function() use ($passwordPolicies) { 154 | return $passwordPolicies; 155 | }); 156 | 157 | $cache->rememberForever('stormpath.resourcesWarm', function() { 158 | return true; 159 | }); 160 | } 161 | 162 | private function loadRoutes() 163 | { 164 | require __DIR__ . '/../Http/routes.php'; 165 | 166 | if(config('stormpath.web.social.enabled')) { 167 | require __DIR__ . '/../Http/socialRoutes.php'; 168 | } 169 | } 170 | 171 | private function registerClient() 172 | { 173 | $id = config( 'stormpath.client.apiKey.id' ); 174 | $secret = config( 'stormpath.client.apiKey.secret' ); 175 | 176 | Client::$apiKeyProperties = "apiKey.id={$id}\napiKey.secret={$secret}"; 177 | Client::$integration = $this->buildAgent(); 178 | 179 | 180 | $this->app->singleton('stormpath.client', function() { 181 | return Client::getInstance(); 182 | }); 183 | } 184 | 185 | private function registerConfig() 186 | { 187 | 188 | $this->publishes([ 189 | __DIR__.'/../config/stormpath.php' => config_path('stormpath.php'), 190 | ]); 191 | 192 | $this->mergeConfigFrom( 193 | __DIR__.'/../config/stormpath.php', 194 | 'stormpath' 195 | ); 196 | } 197 | 198 | private function registerApplication() 199 | { 200 | $this->app->singleton('stormpath.application', function() { 201 | $this->guardAgainstInvalidApplicationHref(); 202 | // return $this->app['cache.store']->rememberForever('stormpath.application', function() { 203 | $application = \Stormpath\Resource\Application::get(config('stormpath.application.href')); 204 | return $application; 205 | // }); 206 | }); 207 | 208 | } 209 | 210 | private function guardAgainstInvalidApplicationhref() 211 | { 212 | if (config('stormpath.application.href') == null) { 213 | throw new \InvalidArgumentException('Application href MUST be set.'); 214 | } 215 | 216 | if (!$this->isValidApplicationHref()) { 217 | throw new \InvalidArgumentException(config('stormpath.application.href') . ' is not a valid Stormpath Application HREF.'); 218 | } 219 | } 220 | 221 | private function registerUser() 222 | { 223 | $this->app->bind('stormpath.user', function($app) { 224 | 225 | try { 226 | $spApplication = app('stormpath.application'); 227 | } catch (\Exception $e) { 228 | return null; 229 | } 230 | 231 | $cookie = $app->request->cookie(config('stormpath.web.accessTokenCookie.name')); 232 | 233 | if(null === $cookie) { 234 | $cookie = $this->refreshCookie($app->request); 235 | } 236 | 237 | try { 238 | if($cookie instanceof \Symfony\Component\HttpFoundation\Cookie) { 239 | $cookie = $cookie->getValue(); 240 | } 241 | $result = (new \Stormpath\Oauth\VerifyAccessToken($spApplication))->verify($cookie); 242 | return $result->getAccount(); 243 | } catch (\Exception $e) {} 244 | 245 | return null; 246 | 247 | }); 248 | } 249 | 250 | private function refreshCookie($request) 251 | { 252 | $cookie = $request->cookie(config('stormpath.web.refreshTokenCookie.name')); 253 | if($cookie instanceof \Symfony\Component\HttpFoundation\Cookie) 254 | $cookie = $cookie->getValue(); 255 | 256 | try { 257 | $refreshGrant = new \Stormpath\Oauth\RefreshGrantRequest($cookie); 258 | $auth = new \Stormpath\Oauth\RefreshGrantAuthenticator(app('stormpath.application')); 259 | $result = $auth->authenticate($refreshGrant); 260 | 261 | $this->setNewAccessToken($request, $result); 262 | 263 | return $result->getAccessTokenString(); 264 | 265 | } catch(\Stormpath\Resource\ResourceError $re) { 266 | return null; 267 | } 268 | } 269 | 270 | private function setNewAccessToken($request, $cookies) 271 | { 272 | $cookieJar = app('cookie'); 273 | $cookieJar->queue( 274 | cookie( 275 | config('stormpath.web.accessTokenCookie.name'), 276 | $cookies->getAccessTokenString(), 277 | $cookies->getExpiresIn(), 278 | config('stormpath.web.accessTokenCookie.path'), 279 | config('stormpath.web.accessTokenCookie.domain'), 280 | config('stormpath.web.accessTokenCookie.secure'), 281 | config('stormpath.web.accessTokenCookie.httpOnly') 282 | ) 283 | 284 | ); 285 | 286 | 287 | $request->cookies->add([config('stormpath.web.accessTokenCookie.name') => $cookies->getAccessTokenString() ]); 288 | 289 | } 290 | 291 | private function isValidApplicationHref() 292 | { 293 | return !! strpos(config( 'stormpath.application.href' ), '/applications/'); 294 | } 295 | 296 | private function setPasswordPolicies() 297 | { 298 | 299 | if(config('stormpath.web.forgotPassword.enabled') == true) return; 300 | 301 | if(config('stormpath.web.changePassword.enabled') == true) return; 302 | 303 | if(config('stormpath.application.href') == null) return; 304 | 305 | config(['stormpath.web.forgotPassword.enabled' => false]); 306 | config(['stormpath.web.forgotPassword.enabled' => false]); 307 | 308 | $cache = $this->app['cache.store']; 309 | 310 | $passwordPolicies = $cache->get('stormpath.passwordPolicies'); 311 | 312 | if($passwordPolicies->getProperty('resetEmailStatus') == Stormpath::ENABLED) { 313 | config(['stormpath.web.forgotPassword.enabled' => true]); 314 | config(['stormpath.web.forgotPassword.enabled' => true]); 315 | return; 316 | } 317 | 318 | } 319 | 320 | private function setAccountCreationPolicy() 321 | { 322 | if(config('stormpath.web.verifyEmail.enabled') == true) return; 323 | 324 | $cache = $this->app['cache.store']; 325 | 326 | if(!$cache->has('stormpath.accountCreationPolicy')) { 327 | $this->warmResources(); 328 | } 329 | 330 | config(['stormpath.web.verifyEmail.enabled' => false]); 331 | 332 | $accountCreationPolicy = $cache->get('stormpath.accountCreationPolicy'); 333 | 334 | if($accountCreationPolicy == null) { 335 | return; 336 | } 337 | 338 | 339 | if($accountCreationPolicy->verificationEmailStatus == Stormpath::ENABLED) { 340 | config(['stormpath.web.verifyEmail.enabled' => true]); 341 | return; 342 | } 343 | 344 | } 345 | 346 | 347 | private function checkForSocialProviders() 348 | { 349 | if(config('stormpath.application.href') == null) return; 350 | 351 | $model = app('cache.store')->rememberForever('stormpath.idsitemodel', function() { 352 | $idSiteModel = $this->getIdSiteModel(); 353 | return IdSiteModel::get($idSiteModel->href); 354 | }); 355 | 356 | $providers = $model->getProperty('providers'); 357 | 358 | 359 | foreach($providers as $provider) { 360 | config(['stormpath.web.social.enabled' => true]); 361 | 362 | switch ($provider->providerId) { 363 | case 'facebook' : 364 | $this->setupFacebookProvider($provider); 365 | break; 366 | case 'google' : 367 | $this->setupGoogleProvider($provider); 368 | break; 369 | case 'github' : 370 | Log::info('Github is not yet supported inside of the Laravel SDK'); 371 | // $this->setupGithubProvider($provider); 372 | break; 373 | case 'linkedin' : 374 | $this->setupLinkedinProvider($provider); 375 | break; 376 | } 377 | } 378 | 379 | 380 | } 381 | 382 | private function getIdSiteModel() 383 | { 384 | $model = app('stormpath.application')->getProperty('idSiteModel'); 385 | 386 | if($model == null) { 387 | throw new \InvalidArgumentException('ID Site could not initialize, please visit ID Site from the Stormpath Dashboard and then clear your cache'); 388 | } 389 | 390 | return $model; 391 | 392 | } 393 | 394 | private function setupFacebookProvider($provider) 395 | { 396 | config(['stormpath.web.social.facebook.enabled' => true]); 397 | config(['stormpath.web.social.facebook.name' => 'Facebook']); 398 | config(['stormpath.web.social.facebook.clientId' => $provider->clientId]); 399 | } 400 | 401 | private function setupGoogleProvider($provider) 402 | { 403 | config(['stormpath.web.social.google.enabled' => true]); 404 | config(['stormpath.web.social.google.name' => 'Google']); 405 | config(['stormpath.web.social.google.clientId' => $provider->clientId]); 406 | config(['stormpath.web.social.google.callbackUri' => $provider->redirectUri]); 407 | } 408 | 409 | // private function setupGithubProvider($provider) 410 | // { 411 | // config(['stormpath.web.social.github.enabled' => true]); 412 | // config(['stormpath.web.social.github.name' => 'Github']); 413 | // config(['stormpath.web.social.github.clientId' => $provider->clientId]); 414 | // } 415 | 416 | private function setupLinkedinProvider($provider) 417 | { 418 | config(['stormpath.web.social.linkedin.enabled' => true]); 419 | config(['stormpath.web.social.linkedin.name' => 'LinkedIn']); 420 | config(['stormpath.web.social.linkedin.clientId' => $provider->clientId]); 421 | 422 | } 423 | 424 | private function buildAgent() 425 | { 426 | $agent = []; 427 | 428 | if(request()->headers->has('X-STORMPATH-AGENT')) { 429 | $agent[] = request()->header('X-STORMPATH-AGENT'); 430 | } 431 | 432 | $laravel = app(); 433 | $version = $laravel::VERSION; 434 | 435 | $agent[] = self::INTEGRATION_NAME . '/' . self::INTEGRATION_VERSION; 436 | $agent[] = 'laravel/' . $version; 437 | 438 | return implode(' ', $agent); 439 | } 440 | 441 | 442 | } 443 | -------------------------------------------------------------------------------- /src/config/stormpath.php: -------------------------------------------------------------------------------- 1 | [ 21 | "apiKey" => [ 22 | "id" => env( 'STORMPATH_CLIENT_APIKEY_ID' ), 23 | "secret" => env( 'STORMPATH_CLIENT_APIKEY_SECRET' ) 24 | ], 25 | "baseUrl" => "https://api.stormpath.com/v1", 26 | "authenticationScheme" => "SAUTHC1" 27 | ], 28 | 29 | "application" => [ 30 | "name" => "", 31 | "href" => env( 'STORMPATH_APPLICATION_HREF' ) 32 | ], 33 | 34 | "web" => [ 35 | 36 | "basePath" => null, 37 | 38 | "oauth2" => [ 39 | "enabled" => true, 40 | "uri" => "/oauth/token", 41 | 42 | "client_credentials" => [ 43 | "enabled" => true, 44 | "accessToken" => [ 45 | "ttl" => 3600 46 | ] 47 | ], 48 | 49 | "password" => [ 50 | "enabled" => true, 51 | "validationStrategy" => "local" 52 | ] 53 | ], 54 | 55 | "accessTokenCookie" => [ 56 | "name" => "access_token", 57 | "httpOnly" => true, 58 | "secure" => null, 59 | "path" => null, 60 | "domain" => null 61 | ], 62 | 63 | "refreshTokenCookie" => [ 64 | "name" => "refresh_token", 65 | "httpOnly" => true, 66 | "secure" => null, 67 | "path" => null, 68 | "domain" => null 69 | ], 70 | 71 | "produces" => [ 72 | "application/json", 73 | "text/html" 74 | ], 75 | 76 | "register" => [ 77 | "enabled" => true, 78 | "uri" => "/register", 79 | "nextUri" => "/", 80 | "autoAuthorize" => false, 81 | "form" => [ 82 | "fields" => [ 83 | "givenName" => [ 84 | "enabled" => true, 85 | "label" => "First Name", 86 | "placeholder" => "First Name", 87 | "required" => true, 88 | "type" => "text" 89 | ], 90 | "middleName" => [ 91 | "enabled" => false, 92 | "label" => "Middle Name", 93 | "placeholder" => "Middle Name", 94 | "required" => true, 95 | "type" => "text" 96 | ], 97 | "surname" => [ 98 | "enabled" => true, 99 | "label" => "Last Name", 100 | "placeholder" => "Last Name", 101 | "required" => true, 102 | "type" => "text" 103 | ], 104 | "username" => [ 105 | "enabled" => false, 106 | "label" => "Username", 107 | "placeholder" => "Username", 108 | "required" => false, 109 | "type" => "text" 110 | ], 111 | "email" => [ 112 | "enabled" => true, 113 | "label" => "Email", 114 | "placeholder" => "Email", 115 | "required" => true, 116 | "type" => "email" 117 | ], 118 | "password" => [ 119 | "enabled" => true, 120 | "label" => "Password", 121 | "placeholder" => "Password", 122 | "required" => true, 123 | "type" => "password" 124 | ], 125 | "confirmPassword" => [ 126 | "enabled" => false, 127 | "label" => "Confirm Password", 128 | "placeholder" => "Confirm Password", 129 | "required" => true, 130 | "type" => "password" 131 | ] 132 | ] 133 | ], 134 | "fieldOrder" => [ 135 | "givenName", 136 | "middleName", 137 | "surname", 138 | "username", 139 | "email", 140 | "password", 141 | "confirmPassword" 142 | ], 143 | "view" => "stormpath::register" 144 | ], 145 | 146 | "verifyEmail" => [ 147 | "uri" => "/verify", 148 | "nextUri" => "/", 149 | "view" => "stormpath::verify" 150 | ], 151 | 152 | "login" => [ 153 | "enabled" => true, 154 | "autoLogin" => true, 155 | "uri" => "/login", 156 | "nextUri" => "/", 157 | "view" => "stormpath::login" 158 | ], 159 | 160 | "logout" => [ 161 | "enabled" => true, 162 | "uri" => "/logout", 163 | "nextUri" => "/" 164 | ], 165 | 166 | "forgotPassword" => [ 167 | "enabled" => null, 168 | "uri" => "/forgot", 169 | "view" => "stormpath::forgot-password", 170 | "nextUri" => "/login?status=forgot" 171 | ], 172 | 173 | "changePassword" => [ 174 | "enabled" => null, 175 | "autoLogin" => false, 176 | "uri" => "/change", 177 | "nextUri" => "/login?status=reset", 178 | "view" => "stormpath::change-password", 179 | "errorUri" => "/forgot?status=invalid_sptoken" 180 | ], 181 | 182 | "idSite" => [ 183 | "enabled" => false, 184 | "uri" => "/idSiteResult", 185 | "nextUri" => "/", 186 | "loginUri" => "", 187 | "forgotUri" => "/#/forgot", 188 | "registerUri" => "/#/register" 189 | ], 190 | 191 | "social" => [ 192 | "facebook" => [ 193 | "uri" => "/callbacks/facebook", 194 | "scope" => "email" 195 | ], 196 | "github" => [ 197 | "uri" => "/callbacks/github", 198 | "scope" => "user:email" 199 | ], 200 | "google" => [ 201 | "uri" => "/callbacks/google", 202 | "scope" => "email, profile" 203 | ], 204 | "linkedin" => [ 205 | "uri" => "/callbacks/linkedin", 206 | "scope" => "r_basicprofile r_emailaddress" 207 | ] 208 | ], 209 | 210 | "me" => [ 211 | "enabled" => true, 212 | "uri" => "/me", 213 | "expand" => [ 214 | "apiKeys" => false, 215 | "applications" => false, 216 | "customData" => false, 217 | "directory" => false, 218 | "groupMemberships" => false, 219 | "groups" => false, 220 | "providerData" => false, 221 | "tenant" => false 222 | ] 223 | ] 224 | 225 | ] 226 | 227 | ]; -------------------------------------------------------------------------------- /src/views/base.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | @yield('title') 11 | 12 | 13 | 14 | 15 | 16 | 407 | 408 | 412 | 413 | 414 | 415 | 416 | @yield('content') 417 | 418 | 419 | 420 | 421 | @yield('footer-scripts') 422 | 423 | 424 | -------------------------------------------------------------------------------- /src/views/change-password.blade.php: -------------------------------------------------------------------------------- 1 | @extends('stormpath::base') 2 | 3 | @section('title', 'Change Your Password') 4 | @section('description', 'Change your password here.') 5 | @section('bodytag', 'login') 6 | 7 | @section('content') 8 |
9 |
10 |
11 |
12 | 66 |
67 |
68 |
69 |
70 | @endsection -------------------------------------------------------------------------------- /src/views/forgot-password.blade.php: -------------------------------------------------------------------------------- 1 | @extends('stormpath::base') 2 | 3 | @section('title', 'Forgot Your Password?') 4 | @section('description', 'Forgot your password? No worries!') 5 | @section('bodytag', 'login') 6 | 7 | @section('content') 8 |
9 |
10 |
11 | 12 | @if(isset($status) && $status == 'invalid_sptoken') 13 |
14 |
15 |

16 | The password reset link you tried to use is no longer valid. 17 | Please request a new link from the form below. 18 |

19 |
20 |
21 | @endif 22 | 23 |
24 | 66 | @if(config('stormpath.web.login.enabled')) 67 | 68 | @endif 69 |
70 |
71 |
72 |
73 | @endsection -------------------------------------------------------------------------------- /src/views/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('stormpath::base') 2 | 3 | @section('title', 'Log In') 4 | @section('description', 'Log into your account!') 5 | @section('bodytag', 'login') 6 | 7 | @if(config('stormpath.web.social.enabled')) 8 | @php 9 | $socialProviders = true; 10 | $areaWrap = 'small col-sm-8'; 11 | $classLabel = 'col-sm-12'; 12 | $classInput = 'col-sm-12'; 13 | @endphp 14 | @else 15 | @php 16 | $socialProviders = false; 17 | $areaWrap = 'small col-sm-12'; 18 | $classLabel = 'col-sm-4'; 19 | $classInput = 'col-sm-8'; 20 | @endphp 21 | @endif 22 | 23 | 24 | @section('content') 25 |
26 |
27 | 95 |
96 |
97 | @endsection -------------------------------------------------------------------------------- /src/views/partials/_loginStatusMessages.blade.php: -------------------------------------------------------------------------------- 1 | @if(isset($status) && View::exists("stormpath::partials.login.{$status}")) 2 |
3 |
4 |
5 | @include("stormpath::partials.login.{$status}") 6 |
7 |
8 |
9 | 10 |
11 | 12 | @endif -------------------------------------------------------------------------------- /src/views/partials/login/created.blade.php: -------------------------------------------------------------------------------- 1 | Your Account Has Been Created 2 |

You may now login.

-------------------------------------------------------------------------------- /src/views/partials/login/forgot.blade.php: -------------------------------------------------------------------------------- 1 | Password Reset Requested 2 |

If an account exists for the email provided, you will 3 | receive an email shortly.

-------------------------------------------------------------------------------- /src/views/partials/login/reset.blade.php: -------------------------------------------------------------------------------- 1 | Password Reset Successfuly 2 |

You can now login with your new password.

-------------------------------------------------------------------------------- /src/views/partials/login/unverified.blade.php: -------------------------------------------------------------------------------- 1 | Your account verification email has been sent! 2 |

3 | Before you can log into your account, you need to activate your 4 | account by clicking the link we sent to your inbox. 5 |

6 |

7 | Didn't get the email? Click Here. 8 |

-------------------------------------------------------------------------------- /src/views/partials/login/verified.blade.php: -------------------------------------------------------------------------------- 1 | Your Account Has Been Verified 2 |

You may now login.

-------------------------------------------------------------------------------- /src/views/partials/social/facebook-login-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/views/partials/social/github-login-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/views/partials/social/google-login-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/views/partials/social/linkedin-login-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/views/partials/social/main.blade.php: -------------------------------------------------------------------------------- 1 | @if(config('stormpath.web.social.facebook') && config('stormpath.web.social.facebook.enabled')) 2 | @include('stormpath::partials.social.facebook-login-form') 3 | @endif 4 | 5 | @if(config('stormpath.web.social.google') && config('stormpath.web.social.google.enabled')) 6 | @include('stormpath::partials.social.google-login-form') 7 | @endif 8 | 9 | @if(config('stormpath.web.social.github') && config('stormpath.web.social.github.enabled')) 10 | @include('stormpath::partials.social.github-login-form') 11 | @endif 12 | 13 | @if(config('stormpath.web.social.linkedin') && config('stormpath.web.social.linkedin.enabled')) 14 | @include('stormpath::partials.social.linkedin-login-form') 15 | @endif -------------------------------------------------------------------------------- /src/views/register.blade.php: -------------------------------------------------------------------------------- 1 | @extends('stormpath::base') 2 | 3 | @section('title', 'Create an Account') 4 | @section('description', 'Create a new account.') 5 | @section('bodytag', 'register') 6 | 7 | @section('content') 8 |
9 |
10 |
11 |
12 |
13 | Create Account 14 |
15 | 16 | @if (isset($errors) && count($errors) > 0) 17 | 22 | @endif 23 | 24 |
26 | {{ csrf_field() }} 27 | 28 | @foreach(config('stormpath.web.register.form.fields') as $name => $field) 29 | @if($field['enabled']) 30 |
31 | 32 |
33 | 39 |
40 |
41 | @endif 42 | @endforeach 43 | 44 | 45 |
46 | 47 |
48 | @if(config('stormpath.web.login.enabled')) 49 | 50 | @endif
51 |
52 |
53 | 54 | @endsection --------------------------------------------------------------------------------