Dan Brown

Updated user interfaces for LDAP and added email from LDAP

...@@ -118,11 +118,22 @@ class AuthController extends Controller ...@@ -118,11 +118,22 @@ class AuthController extends Controller
118 */ 118 */
119 protected function authenticated(Request $request, Authenticatable $user) 119 protected function authenticated(Request $request, Authenticatable $user)
120 { 120 {
121 + if(!$user->exists && $user->email === null && !$request->has('email')) {
122 + $request->flash();
123 + session()->flash('request-email', true);
124 + return redirect('/login');
125 + }
126 +
127 + if(!$user->exists && $user->email === null && $request->has('email')) {
128 + $user->email = $request->get('email');
129 + }
130 +
121 if(!$user->exists) { 131 if(!$user->exists) {
122 $user->save(); 132 $user->save();
123 $this->userRepo->attachDefaultRole($user); 133 $this->userRepo->attachDefaultRole($user);
124 auth()->login($user); 134 auth()->login($user);
125 } 135 }
136 +
126 return redirect()->intended($this->redirectPath()); 137 return redirect()->intended($this->redirectPath());
127 } 138 }
128 139
...@@ -183,7 +194,7 @@ class AuthController extends Controller ...@@ -183,7 +194,7 @@ class AuthController extends Controller
183 } 194 }
184 195
185 /** 196 /**
186 - * Show the page to tell the user to check thier email 197 + * Show the page to tell the user to check their email
187 * and confirm their address. 198 * and confirm their address.
188 */ 199 */
189 public function getRegisterConfirmation() 200 public function getRegisterConfirmation()
...@@ -243,7 +254,7 @@ class AuthController extends Controller ...@@ -243,7 +254,7 @@ class AuthController extends Controller
243 ]); 254 ]);
244 $user = $this->userRepo->getByEmail($request->get('email')); 255 $user = $this->userRepo->getByEmail($request->get('email'));
245 $this->emailConfirmationService->sendConfirmation($user); 256 $this->emailConfirmationService->sendConfirmation($user);
246 - \Session::flash('success', 'Confirmation email resent, Please check your inbox.'); 257 + session()->flash('success', 'Confirmation email resent, Please check your inbox.');
247 return redirect('/register/confirm'); 258 return redirect('/register/confirm');
248 } 259 }
249 260
......
...@@ -46,7 +46,8 @@ class UserController extends Controller ...@@ -46,7 +46,8 @@ class UserController extends Controller
46 public function create() 46 public function create()
47 { 47 {
48 $this->checkPermission('user-create'); 48 $this->checkPermission('user-create');
49 - return view('users/create'); 49 + $authMethod = config('auth.method');
50 + return view('users/create', ['authMethod' => $authMethod]);
50 } 51 }
51 52
52 /** 53 /**
...@@ -94,10 +95,12 @@ class UserController extends Controller ...@@ -94,10 +95,12 @@ class UserController extends Controller
94 return $this->currentUser->id == $id; 95 return $this->currentUser->id == $id;
95 }); 96 });
96 97
98 + $authMethod = config('auth.method');
99 +
97 $user = $this->user->findOrFail($id); 100 $user = $this->user->findOrFail($id);
98 $activeSocialDrivers = $socialAuthService->getActiveDrivers(); 101 $activeSocialDrivers = $socialAuthService->getActiveDrivers();
99 $this->setPageTitle('User Profile'); 102 $this->setPageTitle('User Profile');
100 - return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers]); 103 + return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod]);
101 } 104 }
102 105
103 /** 106 /**
...@@ -124,17 +127,24 @@ class UserController extends Controller ...@@ -124,17 +127,24 @@ class UserController extends Controller
124 ]); 127 ]);
125 128
126 $user = $this->user->findOrFail($id); 129 $user = $this->user->findOrFail($id);
127 - $user->fill($request->except('password')); 130 + $user->fill($request->all());
128 131
132 + // Role updates
129 if ($this->currentUser->can('user-update') && $request->has('role')) { 133 if ($this->currentUser->can('user-update') && $request->has('role')) {
130 $user->attachRoleId($request->get('role')); 134 $user->attachRoleId($request->get('role'));
131 } 135 }
132 136
137 + // Password updates
133 if ($request->has('password') && $request->get('password') != '') { 138 if ($request->has('password') && $request->get('password') != '') {
134 $password = $request->get('password'); 139 $password = $request->get('password');
135 $user->password = bcrypt($password); 140 $user->password = bcrypt($password);
136 } 141 }
137 142
143 + // External auth id updates
144 + if ($this->currentUser->can('user-update') && $request->has('external_auth_id')) {
145 + $user->external_auth_id = $request->get('external_auth_id');
146 + }
147 +
138 $user->save(); 148 $user->save();
139 return redirect('/users'); 149 return redirect('/users');
140 } 150 }
......
...@@ -87,7 +87,6 @@ class LdapUserProvider implements UserProvider ...@@ -87,7 +87,6 @@ class LdapUserProvider implements UserProvider
87 public function updateRememberToken(Authenticatable $user, $token) 87 public function updateRememberToken(Authenticatable $user, $token)
88 { 88 {
89 $user->setRememberToken($token); 89 $user->setRememberToken($token);
90 -
91 $user->save(); 90 $user->save();
92 } 91 }
93 92
...@@ -113,6 +112,7 @@ class LdapUserProvider implements UserProvider ...@@ -113,6 +112,7 @@ class LdapUserProvider implements UserProvider
113 112
114 $model->name = $userDetails['name']; 113 $model->name = $userDetails['name'];
115 $model->external_auth_id = $userDetails['uid']; 114 $model->external_auth_id = $userDetails['uid'];
115 + $model->email = $userDetails['email'];
116 return $model; 116 return $model;
117 } 117 }
118 118
......
...@@ -88,7 +88,7 @@ class UserRepo ...@@ -88,7 +88,7 @@ class UserRepo
88 */ 88 */
89 public function create(array $data) 89 public function create(array $data)
90 { 90 {
91 - return $this->user->create([ 91 + return $this->user->forceCreate([
92 'name' => $data['name'], 92 'name' => $data['name'],
93 'email' => $data['email'], 93 'email' => $data['email'],
94 'password' => bcrypt($data['password']) 94 'password' => bcrypt($data['password'])
......
...@@ -23,7 +23,7 @@ class LdapService ...@@ -23,7 +23,7 @@ class LdapService
23 // Find user 23 // Find user
24 $userFilter = $this->buildFilter(config('services.ldap.user_filter'), ['user' => $userName]); 24 $userFilter = $this->buildFilter(config('services.ldap.user_filter'), ['user' => $userName]);
25 $baseDn = config('services.ldap.base_dn'); 25 $baseDn = config('services.ldap.base_dn');
26 - $ldapSearch = ldap_search($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn']); 26 + $ldapSearch = ldap_search($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', 'mail']);
27 $users = ldap_get_entries($ldapConnection, $ldapSearch); 27 $users = ldap_get_entries($ldapConnection, $ldapSearch);
28 if ($users['count'] === 0) return null; 28 if ($users['count'] === 0) return null;
29 29
...@@ -31,7 +31,8 @@ class LdapService ...@@ -31,7 +31,8 @@ class LdapService
31 return [ 31 return [
32 'uid' => $user['uid'][0], 32 'uid' => $user['uid'][0],
33 'name' => $user['cn'][0], 33 'name' => $user['cn'][0],
34 - 'dn' => $user['dn'] 34 + 'dn' => $user['dn'],
35 + 'email' => (isset($user['mail'])) ? $user['mail'][0] : null
35 ]; 36 ];
36 } 37 }
37 38
......
...@@ -50,13 +50,17 @@ class SettingService ...@@ -50,13 +50,17 @@ class SettingService
50 */ 50 */
51 protected function getValueFromStore($key, $default) 51 protected function getValueFromStore($key, $default)
52 { 52 {
53 + $overrideValue = $this->getOverrideValue($key);
54 + if ($overrideValue !== null) return $overrideValue;
55 +
53 $cacheKey = $this->cachePrefix . $key; 56 $cacheKey = $this->cachePrefix . $key;
54 if ($this->cache->has($cacheKey)) { 57 if ($this->cache->has($cacheKey)) {
55 return $this->cache->get($cacheKey); 58 return $this->cache->get($cacheKey);
56 } 59 }
57 60
58 $settingObject = $this->getSettingObjectByKey($key); 61 $settingObject = $this->getSettingObjectByKey($key);
59 - if($settingObject !== null) { 62 +
63 + if ($settingObject !== null) {
60 $value = $settingObject->value; 64 $value = $settingObject->value;
61 $this->cache->forever($cacheKey, $value); 65 $this->cache->forever($cacheKey, $value);
62 return $value; 66 return $value;
...@@ -65,6 +69,10 @@ class SettingService ...@@ -65,6 +69,10 @@ class SettingService
65 return $default; 69 return $default;
66 } 70 }
67 71
72 + /**
73 + * Clear an item from the cache completely.
74 + * @param $key
75 + */
68 protected function clearFromCache($key) 76 protected function clearFromCache($key)
69 { 77 {
70 $cacheKey = $this->cachePrefix . $key; 78 $cacheKey = $this->cachePrefix . $key;
...@@ -136,9 +144,23 @@ class SettingService ...@@ -136,9 +144,23 @@ class SettingService
136 * @param $key 144 * @param $key
137 * @return mixed 145 * @return mixed
138 */ 146 */
139 - private function getSettingObjectByKey($key) 147 + protected function getSettingObjectByKey($key)
140 { 148 {
141 return $this->setting->where('setting_key', '=', $key)->first(); 149 return $this->setting->where('setting_key', '=', $key)->first();
142 } 150 }
143 151
152 +
153 + /**
154 + * Returns an override value for a setting based on certain app conditions.
155 + * Used where certain configuration options overrule others.
156 + * Returns null if no override value is available.
157 + * @param $key
158 + * @return bool|null
159 + */
160 + protected function getOverrideValue($key)
161 + {
162 + if ($key === 'registration-enabled' && config('auth.method') === 'ldap') return false;
163 + return null;
164 + }
165 +
144 } 166 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -24,7 +24,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon ...@@ -24,7 +24,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
24 * 24 *
25 * @var array 25 * @var array
26 */ 26 */
27 - protected $fillable = ['name', 'email', 'password', 'image_id']; 27 + protected $fillable = ['name', 'email', 'image_id'];
28 28
29 /** 29 /**
30 * The attributes excluded from the model's JSON form. 30 * The attributes excluded from the model's JSON form.
...@@ -68,7 +68,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon ...@@ -68,7 +68,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
68 } 68 }
69 69
70 /** 70 /**
71 - * Loads the user's permissions from thier role. 71 + * Loads the user's permissions from their role.
72 */ 72 */
73 private function loadPermissions() 73 private function loadPermissions()
74 { 74 {
......
...@@ -69,7 +69,7 @@ return [ ...@@ -69,7 +69,7 @@ return [
69 69
70 'providers' => [ 70 'providers' => [
71 'users' => [ 71 'users' => [
72 - 'driver' => env('AUTH_METHOD', 'eloquent'), 72 + 'driver' => env('AUTH_METHOD', 'standard') === 'standard' ? 'eloquent' : env('AUTH_METHOD'),
73 'model' => BookStack\User::class, 73 'model' => BookStack\User::class,
74 ], 74 ],
75 75
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
26 <env name="QUEUE_DRIVER" value="sync"/> 26 <env name="QUEUE_DRIVER" value="sync"/>
27 <env name="DB_CONNECTION" value="mysql_testing"/> 27 <env name="DB_CONNECTION" value="mysql_testing"/>
28 <env name="MAIL_PRETEND" value="true"/> 28 <env name="MAIL_PRETEND" value="true"/>
29 + <env name="AUTH_METHOD" value="standard"/>
29 <env name="DISABLE_EXTERNAL_SERVICES" value="false"/> 30 <env name="DISABLE_EXTERNAL_SERVICES" value="false"/>
30 </php> 31 </php>
31 </phpunit> 32 </phpunit>
......
...@@ -3,6 +3,16 @@ ...@@ -3,6 +3,16 @@
3 @include('form/text', ['name' => 'username', 'tabindex' => 1]) 3 @include('form/text', ['name' => 'username', 'tabindex' => 1])
4 </div> 4 </div>
5 5
6 +@if(session('request-email', false) === true)
7 + <div class="form-group">
8 + <label for="email">Email</label>
9 + @include('form/text', ['name' => 'email', 'tabindex' => 1])
10 + <span class="text-neg">
11 + Please enter an email to use for this account.
12 + </span>
13 + </div>
14 +@endif
15 +
6 <div class="form-group"> 16 <div class="form-group">
7 <label for="password">Password</label> 17 <label for="password">Password</label>
8 @include('form/password', ['name' => 'password', 'tabindex' => 2]) 18 @include('form/password', ['name' => 'password', 'tabindex' => 2])
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
8 8
9 <form action="/users/create" method="post"> 9 <form action="/users/create" method="post">
10 {!! csrf_field() !!} 10 {!! csrf_field() !!}
11 - @include('users/form') 11 + @include('users.forms.' . $authMethod)
12 </form> 12 </form>
13 </div> 13 </div>
14 14
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
25 <h1>Edit {{ $user->id === $currentUser->id ? 'Profile' : 'User' }}</h1> 25 <h1>Edit {{ $user->id === $currentUser->id ? 'Profile' : 'User' }}</h1>
26 {!! csrf_field() !!} 26 {!! csrf_field() !!}
27 <input type="hidden" name="_method" value="put"> 27 <input type="hidden" name="_method" value="put">
28 - @include('users/form', ['model' => $user]) 28 + @include('users.forms.' . $authMethod, ['model' => $user])
29 29
30 </div> 30 </div>
31 <div class="col-md-6"> 31 <div class="col-md-6">
......
1 +<div class="form-group">
2 + <label for="name">Name</label>
3 + @include('form.text', ['name' => 'name'])
4 +</div>
5 +
6 +@if($currentUser->can('user-update'))
7 +<div class="form-group">
8 + <label for="email">Email</label>
9 + @include('form.text', ['name' => 'email'])
10 +</div>
11 +@endif
12 +
13 +@if($currentUser->can('user-update'))
14 + <div class="form-group">
15 + <label for="role">User Role</label>
16 + @include('form.role-select', ['name' => 'role', 'options' => \BookStack\Role::all(), 'displayKey' => 'display_name'])
17 + </div>
18 +@endif
19 +
20 +@if($currentUser->can('user-update'))
21 + <div class="form-group">
22 + <label for="external_auth_id">External Authentication ID</label>
23 + @include('form.text', ['name' => 'external_auth_id'])
24 + </div>
25 +@endif
26 +
27 +<div class="form-group">
28 + <a href="/users" class="button muted">Cancel</a>
29 + <button class="button pos" type="submit">Save</button>
30 +</div>
...\ No newline at end of file ...\ No newline at end of file
1 <div class="form-group"> 1 <div class="form-group">
2 <label for="name">Name</label> 2 <label for="name">Name</label>
3 - @include('form/text', ['name' => 'name']) 3 + @include('form.text', ['name' => 'name'])
4 </div> 4 </div>
5 5
6 <div class="form-group"> 6 <div class="form-group">
7 <label for="email">Email</label> 7 <label for="email">Email</label>
8 - @include('form/text', ['name' => 'email']) 8 + @include('form.text', ['name' => 'email'])
9 </div> 9 </div>
10 10
11 @if($currentUser->can('user-update')) 11 @if($currentUser->can('user-update'))
...@@ -25,12 +25,12 @@ ...@@ -25,12 +25,12 @@
25 25
26 <div class="form-group"> 26 <div class="form-group">
27 <label for="password">Password</label> 27 <label for="password">Password</label>
28 - @include('form/password', ['name' => 'password']) 28 + @include('form.password', ['name' => 'password'])
29 </div> 29 </div>
30 30
31 <div class="form-group"> 31 <div class="form-group">
32 <label for="password-confirm">Confirm Password</label> 32 <label for="password-confirm">Confirm Password</label>
33 - @include('form/password', ['name' => 'password-confirm']) 33 + @include('form.password', ['name' => 'password-confirm'])
34 </div> 34 </div>
35 35
36 <div class="form-group"> 36 <div class="form-group">
......