user_flow = $user_flow; } /** * Start the login flow for a user. * * Redirects the user to the SSO service * * @return mixed */ public function login() { // TODO: Pass in 'previous' URL from session so we can redirect back // if we were redirected to login from a guard? return redirect($this->user_flow->getRedirectUrl(config('authkit.authn.openid.redirect_uri'), config('authkit.authn.scopes'))); } /** * Handle the response from the SSO service. * * Exchange the code for a token and fetches basic user information. * Attempts to log the user into this app, and creates them if they * don't exist. Then redirects the user to the configured post_login url. * * @param Request $request * @return mixed */ public function callback(Request $request) { $user_class = (string)config('auth.providers.users.model'); // Verify the passed in state value $this->user_flow->validateState($request->state); // TODO: Check for error response // Exchange the code for a token $oidc_token = $this->user_flow->exchangeCodeForToken($request->code, config('authkit.authn.openid.redirect_uri')); $user_info = $oidc_token->getUserInfo(); // Try and find a token for that user id $token = Token::where('id', $oidc_token->getUserId())->first(); // If that failed if (!isset($token)) { // No token for that user, either create them or migrate $register_event_result = event(new \authkit2\Events\UserRegistration(null, $user_info)); if (sizeof($register_event_result) == 0) { // If there were no register event handlers then just assume we're using laravel default // stuff and create a user for them. $user = new $user_class(); $user->name = $user_info['name']; $user->email = $user_info['email']; $user->save(); } else { // Otherwise, expect one returned by the event handlers. $user = null; foreach ($register_event_result as $result) { if (is_object($result)) { $user = $result; } } } // TODO: Log a useful error message in these cases if (!isset($user)) { abort(500); // We die() after each abort to help the static analyzer (phan) // along, otherwise it doesn't realize that abort ends execution // and is worried that we've hit the below code in an invalid state. die(); } elseif (!method_exists($user, 'save')) { abort(500); die(); } elseif (!method_exists($user, 'getAuthIdentifierName')) { abort(500); die(); } $token = new Token(); $token->id = $oidc_token->getUserId(); $token->access_token = $oidc_token->getAccessToken(); $refresh_token = $oidc_token->getRefreshToken(); if (!isset($refresh_token)) { abort(500); die(); } $token->refresh_token = $refresh_token; $token->user_id = $user->{$user->getAuthIdentifierName()}; $token->save(); } else { $user = new $user_class(); $user = $user_class::where($user->getAuthIdentifierName(), $token->user_id)->first(); } \Auth::login($user); $login_event_result = event(new \authkit2\Events\UserLogin($user, $user_info)); if (!sizeof($login_event_result)) { if (!isset($user) || !method_exists($user, 'save')) { // TODO: Log a useful error message abort(500); die(); } // If nothing handled the login event, assume we're using laravel default // everything and just go ahead and update the name/email $user->name = $user_info['name']; $user->email = $user_info['email']; $user->save(); } return redirect(url(config('authkit.authn.urls.post_login'))); } /** * Explicitly log out of this application and the SSO service. * * @return mixed */ public function logout() { event(new \authkit2\Events\UserLogout(\Auth::user())); // Log out locally \Auth::logout(); // Redirect to log out remotely as well return redirect($this->user_flow->getLogoutUrl(url(config('authkit.authn.urls.post_logout')))); } }