Altered social auto-reg to be configurable per service
- Added {$service}_AUTO_REGISTER and {$service}_AUTO_CONFIRM_EMAIL env
options for each social auth system.
- Auto-register will allow registration from login, even if registration
is disabled.
- Auto-confirm-email indicates trust and will mark new registrants as
'email_confirmed' and skip 'confirmation email' flow.
- Also added covering tests.
			
			
This commit is contained in:
		
							parent
							
								
									7ad8314bd7
								
							
						
					
					
						commit
						e60d11ee04
					
				| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					<?php namespace BookStack\Exceptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SocialSignInAccountNotUsed extends SocialSignInException
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace BookStack\Http\Controllers\Auth;
 | 
					namespace BookStack\Http\Controllers\Auth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use BookStack\Exceptions\ConfirmationEmailException;
 | 
					use BookStack\Exceptions\SocialSignInAccountNotUsed;
 | 
				
			||||||
use BookStack\Exceptions\SocialSignInException;
 | 
					use BookStack\Exceptions\SocialSignInException;
 | 
				
			||||||
use BookStack\Exceptions\UserRegistrationException;
 | 
					use BookStack\Exceptions\UserRegistrationException;
 | 
				
			||||||
use BookStack\Repos\UserRepo;
 | 
					use BookStack\Repos\UserRepo;
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ use Illuminate\Http\Response;
 | 
				
			||||||
use Validator;
 | 
					use Validator;
 | 
				
			||||||
use BookStack\Http\Controllers\Controller;
 | 
					use BookStack\Http\Controllers\Controller;
 | 
				
			||||||
use Illuminate\Foundation\Auth\RegistersUsers;
 | 
					use Illuminate\Foundation\Auth\RegistersUsers;
 | 
				
			||||||
 | 
					use Laravel\Socialite\Contracts\User as SocialUser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RegisterController extends Controller
 | 
					class RegisterController extends Controller
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -133,25 +134,28 @@ class RegisterController extends Controller
 | 
				
			||||||
     * The registrations flow for all users.
 | 
					     * The registrations flow for all users.
 | 
				
			||||||
     * @param array $userData
 | 
					     * @param array $userData
 | 
				
			||||||
     * @param bool|false|SocialAccount $socialAccount
 | 
					     * @param bool|false|SocialAccount $socialAccount
 | 
				
			||||||
 | 
					     * @param bool $emailVerified
 | 
				
			||||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
     * @throws UserRegistrationException
 | 
					     * @throws UserRegistrationException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected function registerUser(array $userData, $socialAccount = false)
 | 
					    protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (setting('registration-restrict')) {
 | 
					        $registrationRestrict = setting('registration-restrict');
 | 
				
			||||||
            $restrictedEmailDomains = explode(',', str_replace(' ', '', setting('registration-restrict')));
 | 
					
 | 
				
			||||||
 | 
					        if ($registrationRestrict) {
 | 
				
			||||||
 | 
					            $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
 | 
				
			||||||
            $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1);
 | 
					            $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1);
 | 
				
			||||||
            if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
 | 
					            if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
 | 
				
			||||||
                throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
 | 
					                throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $newUser = $this->userRepo->registerNew($userData);
 | 
					        $newUser = $this->userRepo->registerNew($userData, $emailVerified);
 | 
				
			||||||
        if ($socialAccount) {
 | 
					        if ($socialAccount) {
 | 
				
			||||||
            $newUser->socialAccounts()->save($socialAccount);
 | 
					            $newUser->socialAccounts()->save($socialAccount);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (setting('registration-confirmation') || setting('registration-restrict')) {
 | 
					        if ((setting('registration-confirmation') || $registrationRestrict) && !$emailVerified) {
 | 
				
			||||||
            $newUser->save();
 | 
					            $newUser->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
| 
						 | 
					@ -250,7 +254,6 @@ class RegisterController extends Controller
 | 
				
			||||||
     * @throws SocialSignInException
 | 
					     * @throws SocialSignInException
 | 
				
			||||||
     * @throws UserRegistrationException
 | 
					     * @throws UserRegistrationException
 | 
				
			||||||
     * @throws \BookStack\Exceptions\SocialDriverNotConfigured
 | 
					     * @throws \BookStack\Exceptions\SocialDriverNotConfigured
 | 
				
			||||||
     * @throws ConfirmationEmailException
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function socialCallback($socialDriver, Request $request)
 | 
					    public function socialCallback($socialDriver, Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -267,12 +270,24 @@ class RegisterController extends Controller
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $action = session()->pull('social-callback');
 | 
					        $action = session()->pull('social-callback');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Attempt login or fall-back to register if allowed.
 | 
				
			||||||
 | 
					        $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
 | 
				
			||||||
        if ($action == 'login') {
 | 
					        if ($action == 'login') {
 | 
				
			||||||
            return $this->socialAuthService->handleLoginCallback($socialDriver);
 | 
					            try {
 | 
				
			||||||
 | 
					                return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
 | 
				
			||||||
 | 
					            } catch (SocialSignInAccountNotUsed $exception) {
 | 
				
			||||||
 | 
					                if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
 | 
				
			||||||
 | 
					                    return $this->socialRegisterCallback($socialDriver, $socialUser);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                throw $exception;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($action == 'register') {
 | 
					        if ($action == 'register') {
 | 
				
			||||||
            return $this->socialRegisterCallback($socialDriver);
 | 
					            return $this->socialRegisterCallback($socialDriver, $socialUser);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return redirect()->back();
 | 
					        return redirect()->back();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -288,15 +303,16 @@ class RegisterController extends Controller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Register a new user after a registration callback.
 | 
					     * Register a new user after a registration callback.
 | 
				
			||||||
     * @param $socialDriver
 | 
					     * @param string $socialDriver
 | 
				
			||||||
 | 
					     * @param SocialUser $socialUser
 | 
				
			||||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
     * @throws UserRegistrationException
 | 
					     * @throws UserRegistrationException
 | 
				
			||||||
     * @throws \BookStack\Exceptions\SocialDriverNotConfigured
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected function socialRegisterCallback($socialDriver)
 | 
					    protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver);
 | 
					        $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
 | 
				
			||||||
        $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
 | 
					        $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
 | 
				
			||||||
 | 
					        $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Create an array of the user data to create a new user instance
 | 
					        // Create an array of the user data to create a new user instance
 | 
				
			||||||
        $userData = [
 | 
					        $userData = [
 | 
				
			||||||
| 
						 | 
					@ -304,6 +320,6 @@ class RegisterController extends Controller
 | 
				
			||||||
            'email' => $socialUser->getEmail(),
 | 
					            'email' => $socialUser->getEmail(),
 | 
				
			||||||
            'password' => str_random(30)
 | 
					            'password' => str_random(30)
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        return $this->registerUser($userData, $socialAccount);
 | 
					        return $this->registerUser($userData, $socialAccount, $emailVerified);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,12 +79,12 @@ class UserRepo
 | 
				
			||||||
     /**
 | 
					     /**
 | 
				
			||||||
     * Creates a new user and attaches a role to them.
 | 
					     * Creates a new user and attaches a role to them.
 | 
				
			||||||
     * @param array $data
 | 
					     * @param array $data
 | 
				
			||||||
     * @param boolean autoVerifyEmail
 | 
					     * @param boolean $verifyEmail
 | 
				
			||||||
     * @return User
 | 
					     * @return User
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function registerNew(array $data, $autoVerifyEmail=false)
 | 
					    public function registerNew(array $data, $verifyEmail = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $user = $this->create($data, $autoVerifyEmail);
 | 
					        $user = $this->create($data, $verifyEmail);
 | 
				
			||||||
        $this->attachDefaultRole($user);
 | 
					        $this->attachDefaultRole($user);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get avatar from gravatar and save
 | 
					        // Get avatar from gravatar and save
 | 
				
			||||||
| 
						 | 
					@ -142,17 +142,17 @@ class UserRepo
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Create a new basic instance of user.
 | 
					     * Create a new basic instance of user.
 | 
				
			||||||
     * @param array $data
 | 
					     * @param array $data
 | 
				
			||||||
     * @param boolean $autoVerifyEmail
 | 
					     * @param boolean $verifyEmail
 | 
				
			||||||
     * @return User
 | 
					     * @return User
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function create(array $data, $autoVerifyEmail=false)
 | 
					    public function create(array $data, $verifyEmail = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this->user->forceCreate([
 | 
					        return $this->user->forceCreate([
 | 
				
			||||||
            'name'     => $data['name'],
 | 
					            'name'     => $data['name'],
 | 
				
			||||||
            'email'    => $data['email'],
 | 
					            'email'    => $data['email'],
 | 
				
			||||||
            'password' => bcrypt($data['password']),
 | 
					            'password' => bcrypt($data['password']),
 | 
				
			||||||
            'email_confirmed' => $autoVerifyEmail
 | 
					            'email_confirmed' => $verifyEmail
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,12 @@
 | 
				
			||||||
<?php namespace BookStack\Services;
 | 
					<?php namespace BookStack\Services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use BookStack\Http\Requests\Request;
 | 
					use BookStack\Exceptions\SocialSignInAccountNotUsed;
 | 
				
			||||||
use GuzzleHttp\Exception\ClientException;
 | 
					 | 
				
			||||||
use Laravel\Socialite\Contracts\Factory as Socialite;
 | 
					use Laravel\Socialite\Contracts\Factory as Socialite;
 | 
				
			||||||
use BookStack\Exceptions\SocialDriverNotConfigured;
 | 
					use BookStack\Exceptions\SocialDriverNotConfigured;
 | 
				
			||||||
use BookStack\Exceptions\SocialSignInException;
 | 
					 | 
				
			||||||
use BookStack\Exceptions\UserRegistrationException;
 | 
					use BookStack\Exceptions\UserRegistrationException;
 | 
				
			||||||
use BookStack\Repos\UserRepo;
 | 
					use BookStack\Repos\UserRepo;
 | 
				
			||||||
use BookStack\SocialAccount;
 | 
					use BookStack\SocialAccount;
 | 
				
			||||||
 | 
					use Laravel\Socialite\Contracts\User as SocialUser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocialAuthService
 | 
					class SocialAuthService
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -58,18 +57,13 @@ class SocialAuthService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Handle the social registration process on callback.
 | 
					     * Handle the social registration process on callback.
 | 
				
			||||||
     * @param $socialDriver
 | 
					     * @param string $socialDriver
 | 
				
			||||||
     * @return \Laravel\Socialite\Contracts\User
 | 
					     * @param SocialUser $socialUser
 | 
				
			||||||
     * @throws SocialDriverNotConfigured
 | 
					     * @return SocialUser
 | 
				
			||||||
     * @throws UserRegistrationException
 | 
					     * @throws UserRegistrationException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function handleRegistrationCallback($socialDriver)
 | 
					    public function handleRegistrationCallback(string $socialDriver, SocialUser $socialUser)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $driver = $this->validateDriver($socialDriver);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Get user details from social driver
 | 
					 | 
				
			||||||
        $socialUser = $this->socialite->driver($driver)->user();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check social account has not already been used
 | 
					        // Check social account has not already been used
 | 
				
			||||||
        if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) {
 | 
					        if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) {
 | 
				
			||||||
            throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver]), '/login');
 | 
					            throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver]), '/login');
 | 
				
			||||||
| 
						 | 
					@ -84,17 +78,26 @@ class SocialAuthService
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Handle the login process on a oAuth callback.
 | 
					     * Get the social user details via the social driver.
 | 
				
			||||||
     * @param $socialDriver
 | 
					     * @param string $socialDriver
 | 
				
			||||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
					     * @return SocialUser
 | 
				
			||||||
     * @throws SocialDriverNotConfigured
 | 
					     * @throws SocialDriverNotConfigured
 | 
				
			||||||
     * @throws SocialSignInException
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function handleLoginCallback($socialDriver)
 | 
					    public function getSocialUser(string $socialDriver)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $driver = $this->validateDriver($socialDriver);
 | 
					        $driver = $this->validateDriver($socialDriver);
 | 
				
			||||||
        // Get user details from social driver
 | 
					        return $this->socialite->driver($driver)->user();
 | 
				
			||||||
        $socialUser = $this->socialite->driver($driver)->user();
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the login process on a oAuth callback.
 | 
				
			||||||
 | 
					     * @param $socialDriver
 | 
				
			||||||
 | 
					     * @param SocialUser $socialUser
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     * @throws SocialSignInAccountNotUsed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handleLoginCallback($socialDriver, SocialUser $socialUser)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        $socialId = $socialUser->getId();
 | 
					        $socialId = $socialUser->getId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get any attached social accounts or users
 | 
					        // Get any attached social accounts or users
 | 
				
			||||||
| 
						 | 
					@ -109,40 +112,6 @@ class SocialAuthService
 | 
				
			||||||
            return redirect()->intended('/');
 | 
					            return redirect()->intended('/');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // When a user is not logged in and no matching SocialAccount exists,
 | 
					 | 
				
			||||||
        // If the auto social registration is enabled, attach the social account, create new user and log him in.
 | 
					 | 
				
			||||||
        if (!$isLoggedIn && $socialAccount === null && setting('autosocialregistration-confirmation')) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Fill social account
 | 
					 | 
				
			||||||
            $socialAccount = $this->fillSocialAccount($socialDriver, $socialUser);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Create an array of the user data to create a new user instance
 | 
					 | 
				
			||||||
            $userData = [
 | 
					 | 
				
			||||||
                'name' => $socialUser->getName(),
 | 
					 | 
				
			||||||
                'email' => $socialUser->getEmail(),
 | 
					 | 
				
			||||||
                'password' => str_random(30)
 | 
					 | 
				
			||||||
            ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Check domain if domain restriction setting is set
 | 
					 | 
				
			||||||
            if (setting('registration-restrict')) {
 | 
					 | 
				
			||||||
                $restrictedEmailDomains = explode(',', str_replace(' ', '', setting('registration-restrict')));
 | 
					 | 
				
			||||||
                $userEmailDomain = $domain = substr(strrchr($socialUser->getEmail(), "@"), 1);
 | 
					 | 
				
			||||||
                if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
 | 
					 | 
				
			||||||
                    throw new SocialSignInException(trans('auth.registration_email_domain_invalid'), '/login');
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Register new user with autoVerifyEmail set to true and attach the social account
 | 
					 | 
				
			||||||
            $newUser = $this->userRepo->registerNew($userData, true);
 | 
					 | 
				
			||||||
            $newUser->socialAccounts()->save($socialAccount);
 | 
					 | 
				
			||||||
            $newUser->save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Log him in
 | 
					 | 
				
			||||||
            auth()->login($newUser);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return redirect()->intended('/');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // When a user is logged in but the social account does not exist,
 | 
					        // When a user is logged in but the social account does not exist,
 | 
				
			||||||
        // Create the social account and attach it to the user & redirect to the profile page.
 | 
					        // Create the social account and attach it to the user & redirect to the profile page.
 | 
				
			||||||
        if ($isLoggedIn && $socialAccount === null) {
 | 
					        if ($isLoggedIn && $socialAccount === null) {
 | 
				
			||||||
| 
						 | 
					@ -170,7 +139,7 @@ class SocialAuthService
 | 
				
			||||||
            $message .= trans('errors.social_account_register_instructions', ['socialAccount' => title_case($socialDriver)]);
 | 
					            $message .= trans('errors.social_account_register_instructions', ['socialAccount' => title_case($socialDriver)]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        throw new SocialSignInException($message, '/login');
 | 
					        throw new SocialSignInAccountNotUsed($message, '/login');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -232,9 +201,29 @@ class SocialAuthService
 | 
				
			||||||
        return config('services.' . strtolower($driver) . '.name');
 | 
					        return config('services.' . strtolower($driver) . '.name');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the current config for the given driver allows auto-registration.
 | 
				
			||||||
 | 
					     * @param string $driver
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function driverAutoRegisterEnabled(string $driver)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return config('services.' . strtolower($driver) . '.auto_register') === true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the current config for the given driver allow email address auto-confirmation.
 | 
				
			||||||
 | 
					     * @param string $driver
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function driverAutoConfirmEmailEnabled(string $driver)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return config('services.' . strtolower($driver) . '.auto_confirm') === true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param string $socialDriver
 | 
					     * @param string $socialDriver
 | 
				
			||||||
     * @param \Laravel\Socialite\Contracts\User $socialUser
 | 
					     * @param SocialUser $socialUser
 | 
				
			||||||
     * @return SocialAccount
 | 
					     * @return SocialAccount
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function fillSocialAccount($socialDriver, $socialUser)
 | 
					    public function fillSocialAccount($socialDriver, $socialUser)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,8 @@ return [
 | 
				
			||||||
        'client_secret' => env('GITHUB_APP_SECRET', false),
 | 
					        'client_secret' => env('GITHUB_APP_SECRET', false),
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/github/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/github/callback',
 | 
				
			||||||
        'name'          => 'GitHub',
 | 
					        'name'          => 'GitHub',
 | 
				
			||||||
 | 
					        'auto_register' => env('GITHUB_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('GITHUB_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'google'   => [
 | 
					    'google'   => [
 | 
				
			||||||
| 
						 | 
					@ -55,6 +57,8 @@ return [
 | 
				
			||||||
        'client_secret' => env('GOOGLE_APP_SECRET', false),
 | 
					        'client_secret' => env('GOOGLE_APP_SECRET', false),
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/google/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/google/callback',
 | 
				
			||||||
        'name'          => 'Google',
 | 
					        'name'          => 'Google',
 | 
				
			||||||
 | 
					        'auto_register' => env('GOOGLE_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('GOOGLE_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'slack'   => [
 | 
					    'slack'   => [
 | 
				
			||||||
| 
						 | 
					@ -62,6 +66,8 @@ return [
 | 
				
			||||||
        'client_secret' => env('SLACK_APP_SECRET', false),
 | 
					        'client_secret' => env('SLACK_APP_SECRET', false),
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/slack/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/slack/callback',
 | 
				
			||||||
        'name'          => 'Slack',
 | 
					        'name'          => 'Slack',
 | 
				
			||||||
 | 
					        'auto_register' => env('SLACK_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('SLACK_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'facebook'   => [
 | 
					    'facebook'   => [
 | 
				
			||||||
| 
						 | 
					@ -69,6 +75,8 @@ return [
 | 
				
			||||||
        'client_secret' => env('FACEBOOK_APP_SECRET', false),
 | 
					        'client_secret' => env('FACEBOOK_APP_SECRET', false),
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/facebook/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/facebook/callback',
 | 
				
			||||||
        'name'          => 'Facebook',
 | 
					        'name'          => 'Facebook',
 | 
				
			||||||
 | 
					        'auto_register' => env('FACEBOOK_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('FACEBOOK_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'twitter'   => [
 | 
					    'twitter'   => [
 | 
				
			||||||
| 
						 | 
					@ -76,6 +84,8 @@ return [
 | 
				
			||||||
        'client_secret' => env('TWITTER_APP_SECRET', false),
 | 
					        'client_secret' => env('TWITTER_APP_SECRET', false),
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/twitter/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/twitter/callback',
 | 
				
			||||||
        'name'          => 'Twitter',
 | 
					        'name'          => 'Twitter',
 | 
				
			||||||
 | 
					        'auto_register' => env('TWITTER_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('TWITTER_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'azure'   => [
 | 
					    'azure'   => [
 | 
				
			||||||
| 
						 | 
					@ -84,6 +94,8 @@ return [
 | 
				
			||||||
        'tenant'       => env('AZURE_TENANT', false),
 | 
					        'tenant'       => env('AZURE_TENANT', false),
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/azure/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/azure/callback',
 | 
				
			||||||
        'name'          => 'Microsoft Azure',
 | 
					        'name'          => 'Microsoft Azure',
 | 
				
			||||||
 | 
					        'auto_register' => env('AZURE_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('AZURE_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'okta' => [
 | 
					    'okta' => [
 | 
				
			||||||
| 
						 | 
					@ -92,6 +104,8 @@ return [
 | 
				
			||||||
        'redirect' => env('APP_URL') . '/login/service/okta/callback', 
 | 
					        'redirect' => env('APP_URL') . '/login/service/okta/callback', 
 | 
				
			||||||
        'base_url' => env('OKTA_BASE_URL'), 
 | 
					        'base_url' => env('OKTA_BASE_URL'), 
 | 
				
			||||||
        'name'          => 'Okta',
 | 
					        'name'          => 'Okta',
 | 
				
			||||||
 | 
					        'auto_register' => env('OKTA_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('OKTA_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'gitlab' => [
 | 
					    'gitlab' => [
 | 
				
			||||||
| 
						 | 
					@ -100,6 +114,8 @@ return [
 | 
				
			||||||
        'redirect'      => env('APP_URL') . '/login/service/gitlab/callback',
 | 
					        'redirect'      => env('APP_URL') . '/login/service/gitlab/callback',
 | 
				
			||||||
        'instance_uri'  => env('GITLAB_BASE_URI'), // Needed only for self hosted instances
 | 
					        'instance_uri'  => env('GITLAB_BASE_URI'), // Needed only for self hosted instances
 | 
				
			||||||
        'name'          => 'GitLab',
 | 
					        'name'          => 'GitLab',
 | 
				
			||||||
 | 
					        'auto_register' => env('GITLAB_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('GITLAB_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'twitch' => [
 | 
					    'twitch' => [
 | 
				
			||||||
| 
						 | 
					@ -107,12 +123,17 @@ return [
 | 
				
			||||||
        'client_secret' => env('TWITCH_APP_SECRET'),
 | 
					        'client_secret' => env('TWITCH_APP_SECRET'),
 | 
				
			||||||
        'redirect' => env('APP_URL') . '/login/service/twitch/callback',
 | 
					        'redirect' => env('APP_URL') . '/login/service/twitch/callback',
 | 
				
			||||||
        'name'          => 'Twitch',
 | 
					        'name'          => 'Twitch',
 | 
				
			||||||
 | 
					        'auto_register' => env('TWITCH_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('TWITCH_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'discord' => [
 | 
					    'discord' => [
 | 
				
			||||||
        'client_id' => env('DISCORD_APP_ID'),
 | 
					        'client_id' => env('DISCORD_APP_ID'),
 | 
				
			||||||
        'client_secret' => env('DISCORD_APP_SECRET'),
 | 
					        'client_secret' => env('DISCORD_APP_SECRET'),
 | 
				
			||||||
        'redirect' => env('APP_URL') . '/login/service/discord/callback',
 | 
					        'redirect' => env('APP_URL') . '/login/service/discord/callback',
 | 
				
			||||||
        'name' => 'Discord',
 | 
					        'name' => 'Discord',
 | 
				
			||||||
 | 
					        'auto_register' => env('DISCORD_AUTO_REGISTER', false),
 | 
				
			||||||
 | 
					        'auto_confirm' => env('DISCORD_AUTO_CONFIRM_EMAIL', false),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'ldap' => [
 | 
					    'ldap' => [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,8 +35,12 @@
 | 
				
			||||||
        <env name="STORAGE_TYPE" value="local"/>
 | 
					        <env name="STORAGE_TYPE" value="local"/>
 | 
				
			||||||
        <env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
 | 
					        <env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
 | 
				
			||||||
        <env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
					        <env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
				
			||||||
 | 
					        <env name="GITHUB_AUTO_REGISTER" value=""/>
 | 
				
			||||||
 | 
					        <env name="GITHUB_AUTO_CONFIRM_EMAIL" value=""/>
 | 
				
			||||||
        <env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
 | 
					        <env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
 | 
				
			||||||
        <env name="GOOGLE_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
					        <env name="GOOGLE_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
				
			||||||
 | 
					        <env name="GOOGLE_AUTO_REGISTER" value=""/>
 | 
				
			||||||
 | 
					        <env name="GOOGLE_AUTO_CONFIRM_EMAIL" value=""/>
 | 
				
			||||||
        <env name="APP_URL" value="http://bookstack.dev"/>
 | 
					        <env name="APP_URL" value="http://bookstack.dev"/>
 | 
				
			||||||
    </php>
 | 
					    </php>
 | 
				
			||||||
</phpunit>
 | 
					</phpunit>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,8 +43,6 @@ return [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'reg_settings' => 'Registration Settings',
 | 
					    'reg_settings' => 'Registration Settings',
 | 
				
			||||||
    'reg_allow' => 'Allow registration?',
 | 
					    'reg_allow' => 'Allow registration?',
 | 
				
			||||||
    'reg_auto_social_allow'  => 'Allow auto social registration?',
 | 
					 | 
				
			||||||
    'reg_auto_social_allow_desc' => 'If the social user doesn\'t exist, automatically sign him up. Domain restriction is respected if set. Email is also automatically validated for this kind of social registration.',
 | 
					 | 
				
			||||||
    'reg_default_role' => 'Default user role after registration',
 | 
					    'reg_default_role' => 'Default user role after registration',
 | 
				
			||||||
    'reg_confirm_email' => 'Require email confirmation?',
 | 
					    'reg_confirm_email' => 'Require email confirmation?',
 | 
				
			||||||
    'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and the below value will be ignored.',
 | 
					    'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and the below value will be ignored.',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,11 +136,6 @@
 | 
				
			||||||
                                @endforeach
 | 
					                                @endforeach
 | 
				
			||||||
                            </select>
 | 
					                            </select>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                        <div class="form-group">
 | 
					 | 
				
			||||||
                            <label for="setting-autosocialregistration-confirmation">{{ trans('settings.reg_auto_social_allow') }}</label>
 | 
					 | 
				
			||||||
                            <p class="small">{{ trans('settings.reg_auto_social_allow_desc') }}</p>
 | 
					 | 
				
			||||||
                            @include('components.toggle-switch', ['name' => 'setting-autosocialregistration-confirmation', 'value' => setting('autosocialregistration-confirmation')])
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                        <div class="form-group">
 | 
					                        <div class="form-group">
 | 
				
			||||||
                            <label for="setting-registration-confirmation">{{ trans('settings.reg_confirm_email') }}</label>
 | 
					                            <label for="setting-registration-confirmation">{{ trans('settings.reg_confirm_email') }}</label>
 | 
				
			||||||
                            <p class="small">{{ trans('settings.reg_confirm_email_desc') }}</p>
 | 
					                            <p class="small">{{ trans('settings.reg_confirm_email_desc') }}</p>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
<?php namespace Tests;
 | 
					<?php namespace Tests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocialAuthTest extends BrowserKitTest
 | 
					class SocialAuthTest extends TestCase
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function test_social_registration()
 | 
					    public function test_social_registration()
 | 
				
			||||||
| 
						 | 
					@ -25,11 +25,11 @@ class SocialAuthTest extends BrowserKitTest
 | 
				
			||||||
        $mockSocialUser->shouldReceive('getName')->once()->andReturn($user->name);
 | 
					        $mockSocialUser->shouldReceive('getName')->once()->andReturn($user->name);
 | 
				
			||||||
        $mockSocialUser->shouldReceive('getAvatar')->once()->andReturn('avatar_placeholder');
 | 
					        $mockSocialUser->shouldReceive('getAvatar')->once()->andReturn('avatar_placeholder');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->visit('/register/service/google');
 | 
					        $this->get('/register/service/google');
 | 
				
			||||||
        $this->visit('/login/service/google/callback');
 | 
					        $this->get('/login/service/google/callback');
 | 
				
			||||||
        $this->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email]);
 | 
					        $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email]);
 | 
				
			||||||
        $user = $user->whereEmail($user->email)->first();
 | 
					        $user = $user->whereEmail($user->email)->first();
 | 
				
			||||||
        $this->seeInDatabase('social_accounts', ['user_id' => $user->id]);
 | 
					        $this->assertDatabaseHas('social_accounts', ['user_id' => $user->id]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function test_social_login()
 | 
					    public function test_social_login()
 | 
				
			||||||
| 
						 | 
					@ -53,17 +53,21 @@ class SocialAuthTest extends BrowserKitTest
 | 
				
			||||||
        $mockSocialDriver->shouldReceive('redirect')->twice()->andReturn(redirect('/'));
 | 
					        $mockSocialDriver->shouldReceive('redirect')->twice()->andReturn(redirect('/'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Test login routes
 | 
					        // Test login routes
 | 
				
			||||||
        $this->visit('/login')->seeElement('#social-login-google')
 | 
					        $resp = $this->get('/login');
 | 
				
			||||||
            ->click('#social-login-google')
 | 
					        $resp->assertElementExists('a#social-login-google[href$="/login/service/google"]');
 | 
				
			||||||
            ->seePageIs('/login');
 | 
					        $resp = $this->followingRedirects()->get("/login/service/google");
 | 
				
			||||||
 | 
					        $resp->assertSee('login-form');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Test social callback
 | 
					        // Test social callback
 | 
				
			||||||
        $this->visit('/login/service/google/callback')->seePageIs('/login')
 | 
					        $resp = $this->followingRedirects()->get('/login/service/google/callback');
 | 
				
			||||||
            ->see(trans('errors.social_account_not_used', ['socialAccount' => 'Google']));
 | 
					        $resp->assertSee('login-form');
 | 
				
			||||||
 | 
					        $resp->assertSee(trans('errors.social_account_not_used', ['socialAccount' => 'Google']));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $resp = $this->get('/login');
 | 
				
			||||||
 | 
					        $resp->assertElementExists('a#social-login-github[href$="/login/service/github"]');
 | 
				
			||||||
 | 
					        $resp = $this->followingRedirects()->get("/login/service/github");
 | 
				
			||||||
 | 
					        $resp->assertSee('login-form');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->visit('/login')->seeElement('#social-login-github')
 | 
					 | 
				
			||||||
        ->click('#social-login-github')
 | 
					 | 
				
			||||||
        ->seePageIs('/login');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Test social callback with matching social account
 | 
					        // Test social callback with matching social account
 | 
				
			||||||
        \DB::table('social_accounts')->insert([
 | 
					        \DB::table('social_accounts')->insert([
 | 
				
			||||||
| 
						 | 
					@ -71,7 +75,77 @@ class SocialAuthTest extends BrowserKitTest
 | 
				
			||||||
            'driver' => 'github',
 | 
					            'driver' => 'github',
 | 
				
			||||||
            'driver_id' => 'logintest123'
 | 
					            'driver_id' => 'logintest123'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $this->visit('/login/service/github/callback')->seePageIs('/');
 | 
					        $resp = $this->followingRedirects()->get('/login/service/github/callback');
 | 
				
			||||||
 | 
					        $resp->assertDontSee("login-form");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_social_autoregister()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config([
 | 
				
			||||||
 | 
					            'services.google.client_id' => 'abc123', 'services.google.client_secret' => '123abc',
 | 
				
			||||||
 | 
					            'APP_URL' => 'http://localhost'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user = factory(\BookStack\User::class)->make();
 | 
				
			||||||
 | 
					        $mockSocialite = \Mockery::mock('Laravel\Socialite\Contracts\Factory');
 | 
				
			||||||
 | 
					        $this->app['Laravel\Socialite\Contracts\Factory'] = $mockSocialite;
 | 
				
			||||||
 | 
					        $mockSocialDriver = \Mockery::mock('Laravel\Socialite\Contracts\Provider');
 | 
				
			||||||
 | 
					        $mockSocialUser = \Mockery::mock('\Laravel\Socialite\Contracts\User');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getId')->times(4)->andReturn(1);
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getEmail')->times(2)->andReturn($user->email);
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getName')->once()->andReturn($user->name);
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getAvatar')->once()->andReturn('avatar_placeholder');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $mockSocialDriver->shouldReceive('user')->times(2)->andReturn($mockSocialUser);
 | 
				
			||||||
 | 
					        $mockSocialite->shouldReceive('driver')->times(4)->with('google')->andReturn($mockSocialDriver);
 | 
				
			||||||
 | 
					        $mockSocialDriver->shouldReceive('redirect')->twice()->andReturn(redirect('/'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $googleAccountNotUsedMessage = trans('errors.social_account_not_used', ['socialAccount' => 'Google']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->get('/login/service/google');
 | 
				
			||||||
 | 
					        $resp = $this->followingRedirects()->get('/login/service/google/callback');
 | 
				
			||||||
 | 
					        $resp->assertSee($googleAccountNotUsedMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config(['services.google.auto_register' => true]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->get('/login/service/google');
 | 
				
			||||||
 | 
					        $resp = $this->followingRedirects()->get('/login/service/google/callback');
 | 
				
			||||||
 | 
					        $resp->assertDontSee($googleAccountNotUsedMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
 | 
				
			||||||
 | 
					        $user = $user->whereEmail($user->email)->first();
 | 
				
			||||||
 | 
					        $this->assertDatabaseHas('social_accounts', ['user_id' => $user->id]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_social_auto_email_confirm()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config([
 | 
				
			||||||
 | 
					            'services.google.client_id' => 'abc123', 'services.google.client_secret' => '123abc',
 | 
				
			||||||
 | 
					            'APP_URL' => 'http://localhost', 'services.google.auto_register' => true, 'services.google.auto_confirm' => true
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user = factory(\BookStack\User::class)->make();
 | 
				
			||||||
 | 
					        $mockSocialite = \Mockery::mock('Laravel\Socialite\Contracts\Factory');
 | 
				
			||||||
 | 
					        $this->app['Laravel\Socialite\Contracts\Factory'] = $mockSocialite;
 | 
				
			||||||
 | 
					        $mockSocialDriver = \Mockery::mock('Laravel\Socialite\Contracts\Provider');
 | 
				
			||||||
 | 
					        $mockSocialUser = \Mockery::mock('\Laravel\Socialite\Contracts\User');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getId')->times(3)->andReturn(1);
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getEmail')->times(2)->andReturn($user->email);
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getName')->once()->andReturn($user->name);
 | 
				
			||||||
 | 
					        $mockSocialUser->shouldReceive('getAvatar')->once()->andReturn('avatar_placeholder');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $mockSocialDriver->shouldReceive('user')->times(1)->andReturn($mockSocialUser);
 | 
				
			||||||
 | 
					        $mockSocialite->shouldReceive('driver')->times(2)->with('google')->andReturn($mockSocialDriver);
 | 
				
			||||||
 | 
					        $mockSocialDriver->shouldReceive('redirect')->once()->andReturn(redirect('/'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->get('/login/service/google');
 | 
				
			||||||
 | 
					        $this->get('/login/service/google/callback');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => true]);
 | 
				
			||||||
 | 
					        $user = $user->whereEmail($user->email)->first();
 | 
				
			||||||
 | 
					        $this->assertDatabaseHas('social_accounts', ['user_id' => $user->id]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue