]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/RegisterController.php
Added icon for saml, added saml to register page, updated complete env
[bookstack] / app / Http / Controllers / Auth / RegisterController.php
1 <?php
2
3 namespace BookStack\Http\Controllers\Auth;
4
5 use BookStack\Auth\Access\EmailConfirmationService;
6 use BookStack\Auth\Access\SocialAuthService;
7 use BookStack\Auth\SocialAccount;
8 use BookStack\Auth\User;
9 use BookStack\Auth\UserRepo;
10 use BookStack\Exceptions\SocialDriverNotConfigured;
11 use BookStack\Exceptions\SocialSignInAccountNotUsed;
12 use BookStack\Exceptions\SocialSignInException;
13 use BookStack\Exceptions\UserRegistrationException;
14 use BookStack\Http\Controllers\Controller;
15 use Exception;
16 use Illuminate\Foundation\Auth\RegistersUsers;
17 use Illuminate\Http\RedirectResponse;
18 use Illuminate\Http\Request;
19 use Illuminate\Http\Response;
20 use Illuminate\Routing\Redirector;
21 use Illuminate\Support\Facades\Hash;
22 use Illuminate\Support\Str;
23 use Laravel\Socialite\Contracts\User as SocialUser;
24 use Validator;
25
26 class RegisterController extends Controller
27 {
28     /*
29     |--------------------------------------------------------------------------
30     | Register Controller
31     |--------------------------------------------------------------------------
32     |
33     | This controller handles the registration of new users as well as their
34     | validation and creation. By default this controller uses a trait to
35     | provide this functionality without requiring any additional code.
36     |
37     */
38
39     use RegistersUsers;
40
41     protected $socialAuthService;
42     protected $emailConfirmationService;
43     protected $userRepo;
44
45     /**
46      * Where to redirect users after login / registration.
47      *
48      * @var string
49      */
50     protected $redirectTo = '/';
51     protected $redirectPath = '/';
52
53     /**
54      * Create a new controller instance.
55      *
56      * @param SocialAuthService $socialAuthService
57      * @param EmailConfirmationService $emailConfirmationService
58      * @param UserRepo $userRepo
59      */
60     public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
61     {
62         $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']);
63         $this->socialAuthService = $socialAuthService;
64         $this->emailConfirmationService = $emailConfirmationService;
65         $this->userRepo = $userRepo;
66         $this->redirectTo = url('/');
67         $this->redirectPath = url('/');
68         parent::__construct();
69     }
70
71     /**
72      * Get a validator for an incoming registration request.
73      *
74      * @param  array $data
75      * @return \Illuminate\Contracts\Validation\Validator
76      */
77     protected function validator(array $data)
78     {
79         return Validator::make($data, [
80             'name' => 'required|min:2|max:255',
81             'email' => 'required|email|max:255|unique:users',
82             'password' => 'required|min:8',
83         ]);
84     }
85
86     /**
87      * Check whether or not registrations are allowed in the app settings.
88      * @throws UserRegistrationException
89      */
90     protected function checkRegistrationAllowed()
91     {
92         if (!setting('registration-enabled')) {
93             throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login');
94         }
95     }
96
97     /**
98      * Show the application registration form.
99      * @return Response
100      * @throws UserRegistrationException
101      */
102     public function getRegister()
103     {
104         $this->checkRegistrationAllowed();
105         $socialDrivers = $this->socialAuthService->getActiveDrivers();
106         $samlEnabled = (config('saml2.enabled') === true) && (config('saml2.auto_register') === true);
107         return view('auth.register', [
108             'socialDrivers' => $socialDrivers,
109             'samlEnabled' => $samlEnabled,
110         ]);
111     }
112
113     /**
114      * Handle a registration request for the application.
115      * @param Request|Request $request
116      * @return RedirectResponse|Redirector
117      * @throws UserRegistrationException
118      */
119     public function postRegister(Request $request)
120     {
121         $this->checkRegistrationAllowed();
122         $this->validator($request->all())->validate();
123
124         $userData = $request->all();
125         return $this->registerUser($userData);
126     }
127
128     /**
129      * Create a new user instance after a valid registration.
130      * @param  array  $data
131      * @return User
132      */
133     protected function create(array $data)
134     {
135         return User::create([
136             'name' => $data['name'],
137             'email' => $data['email'],
138             'password' => Hash::make($data['password']),
139         ]);
140     }
141
142     /**
143      * The registrations flow for all users.
144      * @param array $userData
145      * @param bool|false|SocialAccount $socialAccount
146      * @param bool $emailVerified
147      * @return RedirectResponse|Redirector
148      * @throws UserRegistrationException
149      */
150     protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
151     {
152         $registrationRestrict = setting('registration-restrict');
153
154         if ($registrationRestrict) {
155             $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
156             $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1);
157             if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
158                 throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
159             }
160         }
161
162         $newUser = $this->userRepo->registerNew($userData, $emailVerified);
163         if ($socialAccount) {
164             $newUser->socialAccounts()->save($socialAccount);
165         }
166
167         if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) {
168             $newUser->save();
169
170             try {
171                 $this->emailConfirmationService->sendConfirmation($newUser);
172             } catch (Exception $e) {
173                 $this->showErrorNotification(trans('auth.email_confirm_send_error'));
174             }
175
176             return redirect('/register/confirm');
177         }
178
179         auth()->login($newUser);
180         $this->showSuccessNotification(trans('auth.register_success'));
181         return redirect($this->redirectPath());
182     }
183
184     /**
185      * Redirect to the social site for authentication intended to register.
186      * @param $socialDriver
187      * @return mixed
188      * @throws UserRegistrationException
189      * @throws SocialDriverNotConfigured
190      */
191     public function socialRegister($socialDriver)
192     {
193         $this->checkRegistrationAllowed();
194         session()->put('social-callback', 'register');
195         return $this->socialAuthService->startRegister($socialDriver);
196     }
197
198     /**
199      * The callback for social login services.
200      * @param Request $request
201      * @param string $socialDriver
202      * @return RedirectResponse|Redirector
203      * @throws SocialSignInException
204      * @throws UserRegistrationException
205      * @throws SocialDriverNotConfigured
206      */
207     public function socialCallback(Request $request, string $socialDriver)
208     {
209         if (!session()->has('social-callback')) {
210             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
211         }
212
213         // Check request for error information
214         if ($request->has('error') && $request->has('error_description')) {
215             throw new SocialSignInException(trans('errors.social_login_bad_response', [
216                 'socialAccount' => $socialDriver,
217                 'error' => $request->get('error_description'),
218             ]), '/login');
219         }
220
221         $action = session()->pull('social-callback');
222
223         // Attempt login or fall-back to register if allowed.
224         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
225         if ($action == 'login') {
226             try {
227                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
228             } catch (SocialSignInAccountNotUsed $exception) {
229                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
230                     return $this->socialRegisterCallback($socialDriver, $socialUser);
231                 }
232                 throw $exception;
233             }
234         }
235
236         if ($action == 'register') {
237             return $this->socialRegisterCallback($socialDriver, $socialUser);
238         }
239
240         return redirect()->back();
241     }
242
243     /**
244      * Detach a social account from a user.
245      * @param $socialDriver
246      * @return RedirectResponse|Redirector
247      */
248     public function detachSocialAccount($socialDriver)
249     {
250         return $this->socialAuthService->detachSocialAccount($socialDriver);
251     }
252
253     /**
254      * Register a new user after a registration callback.
255      * @param string $socialDriver
256      * @param SocialUser $socialUser
257      * @return RedirectResponse|Redirector
258      * @throws UserRegistrationException
259      */
260     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
261     {
262         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
263         $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
264         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
265
266         // Create an array of the user data to create a new user instance
267         $userData = [
268             'name' => $socialUser->getName(),
269             'email' => $socialUser->getEmail(),
270             'password' => Str::random(30)
271         ];
272         return $this->registerUser($userData, $socialAccount, $emailVerified);
273     }
274 }