userService = $userService; $this->memberService = $memberService; $this->middleware('auth:sanctum', [ 'except' => [ 'get_sso_data', 'login', 'signup', 'sso', 'status', ], ]); } public function login(Login $request) { if (empty($request->token)) { $user = $this->userService->getByEmailWith($request->email, ['roles']); if (!$user || !Hash::check($request->password, $user->password)) { return response(['error' => ['The provided credentials are incorrect.']]); } } else { $client = new \GuzzleHttp\Client(['base_uri' => static::determineIdpUri()]); $headers = [ 'Authorization' => 'Bearer ' . $request->token, 'Accept' => 'application/json', ]; try { $response = $client->request('GET', 'oidc/userinfo.php', [ 'headers' => $headers ]); } catch (ClientException $e) { $html = 'Login faild with token:' . $request->token; Mail::send([], [], function ($message) use ($html) { $message ->to('jasper@3110.nl') ->subject('Login failed via SSO') ->setBody($html, 'text/html'); }); } $data = $response->getBody()->getContents(); $data = json_decode($data); if (empty($data->profile) || !stristr($data->profile, 'KG')) { return response(['error' => ['The provided credentials are incorrect.']]); } $profile_arr = explode(',', $data->profile); $organization_id = str_replace('KG_', '', $profile_arr[0]); $member = $this->memberService->get($organization_id); $user = $this->userService->getByEmailWith($data->sub, ['roles']); if (!$user) { $new_user = [ 'first_name' => $data->given_name, 'last_name' => $data->family_name, 'email' => $data->sub, 'password' => 'aT@5*Wb*W7gseVhC', ]; $user = $this->userService->save($new_user, false); $user->roles()->attach(Role::whereName('user')->firstOrFail()); } $member->users()->syncWithoutDetaching([$user->id]); $member->save(); } $user->last_login_at = $user->logged_at; $user->last_login_ip = $request->getClientIp(); $user->logged_at = Carbon::now(); $user->save(); $token = $user->createToken('cms-token')->plainTextToken; $response = ['token' => $token]; return response($response, 201); } public function logout(Request $request) { $request->user()->tokens()->delete(); return response()->json('Logged-out', 201); } public function status(Request $request) { $bearerToken = $request->bearerToken(); if (is_null($bearerToken)) { return ApiResponse::error( new Error\AuthController\MissingBearerTokenError(), ); } else { $accessToken = PersonalAccessToken::findToken($bearerToken); return ApiResponse::success([ 'authenticated' => $accessToken instanceof PersonalAccessToken, 'user' => $accessToken ? $accessToken->tokenable->email : null, ]); } } public function me(Request $request) { return response()->json(new UserLoggedResource($request->user())); } private static function dumpLocal(...$values): void { if (static::isLocal()) { dd(...$values); } } private static function isLocal(): bool { return $_SERVER['REMOTE_ADDR'] === '89.98.81.170'; } public function sso() { $cookieFileHandle = tmpfile(); $cookieFilePath = stream_get_meta_data($cookieFileHandle)['uri']; $ch = curl_init(static::buildSsoEndpointUri()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_COOKIESESSION, true); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFilePath); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFilePath); $result = curl_exec($ch); curl_close($ch); fclose($cookieFileHandle); if (static::isLocal()) { echo $result; exit; } echo '
'; } private static function buildSsoEndpointUri(): string { $endpointQuery = http_build_query([ 'client_id' => config('sso.client_id'), 'redirect_uri' => config('sso.redirect_uri'), 'scope' => implode('+', config('sso.scopes')), 'response_type' => 'id_token+token', 'response_mode' => 'form_post', 'nonce' => md5(rand()), // TODO: proper nonce handling ], '', '&', PHP_QUERY_RFC3986); $endpointQuery = str_replace('%2B', '+', $endpointQuery); return sprintf('%s?%s', static::determineIdpUri('oidc/authorize.php'), $endpointQuery); } private static function determineIdpUri(string $path = ''): string { $baseUri = rtrim(config('sso.idp_base_uri'), '/'); return sprintf('%s/%s', $baseUri, $path); } public function get_sso_data() { $client = new \GuzzleHttp\Client([ 'base_uri' => static::determineIdpUri(), 'headers' => [ 'Authorization' => sprintf('Bearer %s', $_GET['token']), 'Accept' => 'application/json', ], ]); $response = $client->request('GET', 'oidc/userinfo.php'); return response($response->getBody()->getContents(), 201); } }