]> git.mxchange.org Git - pizzaservice-war.git/blob - src/java/org/mxchange/pizzaapplication/beans/user/login/PizzaUserLoginWebSessionBean.java
Updated copyright year
[pizzaservice-war.git] / src / java / org / mxchange / pizzaapplication / beans / user / login / PizzaUserLoginWebSessionBean.java
1 /*
2  * Copyright (C) 2016 - 2024 Free Software Foundation
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Affero General Public License as
6  * published by the Free Software Foundation, either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Affero General Public License for more details.
13  *
14  * You should have received a copy of the GNU Affero General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 package org.mxchange.pizzaapplication.beans.user.login;
18
19 import java.text.MessageFormat;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Objects;
23 import javax.ejb.EJB;
24 import javax.enterprise.context.SessionScoped;
25 import javax.enterprise.event.Event;
26 import javax.enterprise.event.Observes;
27 import javax.enterprise.inject.Any;
28 import javax.faces.context.FacesContext;
29 import javax.inject.Inject;
30 import javax.inject.Named;
31 import org.mxchange.jusercore.exceptions.UserNotFoundException;
32 import org.mxchange.jusercore.exceptions.UserStatusLockedException;
33 import org.mxchange.jusercore.exceptions.UserStatusUnconfirmedException;
34 import org.mxchange.jusercore.model.user.User;
35 import org.mxchange.jusercore.model.user.password_history.PasswordHistory;
36 import org.mxchange.jusercore.model.user.password_history.UserPasswordHistorySessionBeanRemote;
37 import org.mxchange.jusercore.model.user.profilemodes.ProfileMode;
38 import org.mxchange.jusercore.model.user.status.UserAccountStatus;
39 import org.mxchange.juserlogincore.container.login.LoginContainer;
40 import org.mxchange.juserlogincore.container.login.UserLoginContainer;
41 import org.mxchange.juserlogincore.events.login.ObservableUserLoggedInEvent;
42 import org.mxchange.juserlogincore.events.login.UserLoggedInEvent;
43 import org.mxchange.juserlogincore.events.logout.ObservableUserLogoutEvent;
44 import org.mxchange.juserlogincore.events.logout.UserLogoutEvent;
45 import org.mxchange.juserlogincore.events.user.password_change.ObservableUpdatedUserPasswordEvent;
46 import org.mxchange.juserlogincore.exceptions.UserPasswordMismatchException;
47 import org.mxchange.juserlogincore.model.user.login.UserLoginSessionBeanRemote;
48 import org.mxchange.juserlogincore.utils.UserLoginUtils;
49 import org.mxchange.pizzaapplication.beans.BasePizzaBean;
50 import org.mxchange.pizzaapplication.beans.user.PizzaUserWebRequestController;
51
52 /**
53  * A web bean for user registration
54  * <p>
55  * @author Roland Häder<roland@mxchange.org>
56  */
57 @Named ("userLoginController")
58 @SessionScoped
59 public class PizzaUserLoginWebSessionBean extends BasePizzaBean implements PizzaUserLoginWebSessionController {
60
61         /**
62          * Path name for guest base template
63          */
64         private static final String GUEST_BASE_TEMPLATE_NAME = "guest/guest";
65
66         /**
67          * Path name for logged-in user base template
68          */
69         private static final String USER_BASE_TEMPLATE_NAME = "login/user/user";
70
71         /**
72          * Serial number
73          */
74         private static final long serialVersionUID = 47_828_986_719_691_592L;
75
76         /**
77          * Template type for pages that might be displayed in guest area and login
78          * area.
79          */
80         private String baseTemplatePathName;
81
82         /**
83          * Logged-in user instance
84          */
85         private User loggedInUser;
86
87         /**
88          * Event fired when user has logged in
89          */
90         @Inject
91         @Any
92         private Event<ObservableUserLoggedInEvent> loginEvent;
93
94         /**
95          * User controller
96          */
97         @Inject
98         private PizzaUserWebRequestController userController;
99
100         /**
101          * Current password
102          */
103         private String userCurrentPassword;
104
105         /**
106          * Flag whether the user has logged-in, set only from inside
107          */
108         private boolean userLoggedIn;
109
110         /**
111          * Remote register session-scoped bean
112          */
113         @EJB (lookup = "java:global/addressbook-ejb/userLogin!org.mxchange.juserlogincore.model.user.login.UserLoginSessionBeanRemote")
114         private UserLoginSessionBeanRemote userLoginBean;
115
116         /**
117          * Event fired when user has logged in
118          */
119         @Inject
120         @Any
121         private Event<ObservableUserLoggedInEvent> userLoginEvent;
122
123         /**
124          * Event fired when user has logged out
125          */
126         @Inject
127         @Any
128         private Event<ObservableUserLogoutEvent> userLogoutEvent;
129
130         /**
131          * User's password history
132          */
133         private List<PasswordHistory> userPasswordHistory;
134
135         /**
136          * EJB for user's password history
137          */
138         @EJB (lookup = "java:global/addressbook-ejb/userPasswordHistory!org.mxchange.jusercore.model.user.password_history.UserPasswordHistorySessionBeanRemote")
139         private UserPasswordHistorySessionBeanRemote userPasswordHistoryBean;
140
141         /**
142          * Default constructor
143          */
144         public PizzaUserLoginWebSessionBean () {
145                 // Call super constructor
146                 super();
147
148                 // Defaul template is guest
149                 this.baseTemplatePathName = GUEST_BASE_TEMPLATE_NAME;
150         }
151
152         /**
153          * Method being call after user's password has been updated (and history
154          * entry has been created).
155          * <p>
156          * @param event Event being observed
157          */
158         public void afterUserUpdatedPasswordEvent (@Observes final ObservableUpdatedUserPasswordEvent event) {
159                 // Check parameter
160                 if (null == event) {
161                         // Throw NPE
162                         throw new NullPointerException("event is null"); //NOI18N
163                 } else if (event.getPasswordHistory() == null) {
164                         // Throw NPE again
165                         throw new NullPointerException("event.passwordHistory is null"); //NOI18N
166                 } else if (event.getPasswordHistory().getUserPasswordHistoryId() == null) {
167                         // ... and again
168                         throw new NullPointerException("event.passwordHistory.userPasswordHistoryId is null"); //NOI18N
169                 } else if (event.getPasswordHistory().getUserPasswordHistoryId() < 1) {
170                         // Invalid value
171                         throw new IllegalArgumentException(MessageFormat.format("event.passwordHistory.userPasswordHistoryId={0} is in valid", event.getPasswordHistory().getUserPasswordHistoryId())); //NOI18N
172                 }
173
174                 // Get user instance
175                 final User user = event.getCreatedUser();
176
177                 // Set all fields here
178                 this.copyToUser(user);
179         }
180
181         /**
182          * Event observer for logged-in user
183          * <p>
184          * @param event Event instance
185          */
186         public void afterUserLoginEvent (@Observes final ObservableUserLoggedInEvent event) {
187                 // Event and contained entity instance should not be null
188                 if (null == event) {
189                         // Throw NPE
190                         throw new NullPointerException("event is null"); //NOI18N
191                 } else if (event.getLoggedInUser() == null) {
192                         // Throw NPE again
193                         throw new NullPointerException("event.registeredUser is null"); //NOI18N
194                 } else if (event.getLoggedInUser().getUserId() == null) {
195                         // userId is null
196                         throw new NullPointerException("event.registeredUser.userId is null"); //NOI18N
197                 } else if (event.getLoggedInUser().getUserId() < 1) {
198                         // Not avalid id
199                         throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getLoggedInUser(), event.getLoggedInUser().getUserId())); //NOI18N
200                 }
201
202                 // "Cache" user instance
203                 final User user = event.getLoggedInUser();
204
205                 // Copy all data to this bean
206                 this.copyToUser(user);
207         }
208
209         /**
210          * Event observer for user password changes
211          * <p>
212          * @param event Event being fired
213          */
214         public void afterUserPasswordChangedEvent (@Observes final ObservableUpdatedUserPasswordEvent event) {
215                 // Is it valid?
216                 if (null == event) {
217                         // Throw NPE
218                         throw new NullPointerException("event is null"); //NOI18N
219                 } else if (event.getUserPassword() == null) {
220                         // Throw NPE
221                         throw new NullPointerException("event.userPassword is null"); //NOI18N
222                 } else if (event.getUserPassword().isEmpty()) {
223                         // Throw NPE
224                         throw new IllegalArgumentException("event.userPassword is empty"); //NOI18N
225                 }
226
227                 // Set it here
228                 this.setUserPassword(event.getUserPassword());
229                 this.updatePasswordHistory(event.getPasswordHistory());
230         }
231
232         /**
233          * Event observer for new user registrations
234          * <p>
235          * @param event User registration event
236          */
237         public void afterUserRegistrationEvent (@Observes final ObservableUserRegisteredEvent event) {
238                 // Event and contained entity instance should not be null
239                 if (null == event) {
240                         // Throw NPE
241                         throw new NullPointerException("event is null"); //NOI18N
242                 } else if (event.getRegisteredUser() == null) {
243                         // Throw NPE again
244                         throw new NullPointerException("event.registeredUser is null"); //NOI18N
245                 } else if (event.getRegisteredUser().getUserId() == null) {
246                         // userId is null
247                         throw new NullPointerException("event.registeredUser.userId is null"); //NOI18N
248                 } else if (event.getRegisteredUser().getUserId() < 1) {
249                         // Not avalid id
250                         throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getRegisteredUser(), event.getRegisteredUser().getUserId())); //NOI18N
251                 }
252
253                 // Get user instance
254                 final User registeredUser = event.getRegisteredUser();
255
256                 // Copy all data from registered->user
257                 this.copyToUser(registeredUser);
258
259                 // Set user id again
260                 this.setUserId(registeredUser.getUserId());
261         }
262
263         /**
264          * Logout for administrator area. If a logged-in user instance exists, it is
265          * being logged-out, too.
266          * <p>
267          * @return Outcome (should be redirected)
268          */
269         public String doAdminLogout () {
270                 // Is a user logged-in?
271                 if (this.isUserLoggedIn()) {
272                         // Call other logout
273                         return this.doUserLogout();
274                 }
275
276                 // Invalidate session
277                 FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
278
279                 // Set template type to guest
280                 this.setBaseTemplatePathName(GUEST_BASE_TEMPLATE_NAME); //NOI18N
281
282                 // Redirect to index
283                 return "index?faces-redirect=true"; //NOI18N
284         }
285
286         /**
287          * Logins the user, if the account is found, confirmed and unlocked.
288          * <p>
289          * @return Redirect target
290          */
291         public String doUserLogin () {
292                 // Get user instance
293                 final User user = this.userController.createUserLogin();
294
295                 // Create login container
296                 final LoginContainer loginContainer = new UserLoginContainer(user, this.userController.getUserPassword());
297
298                 try {
299                         // Call bean
300                         final User confirmedUser = this.userLoginBean.validateUserAccountStatus(loginContainer);
301
302                         // All fine here so set it here
303                         this.setLoggedInUser(confirmedUser);
304
305                         // Retrieve user's password list
306                         this.userPasswordHistory = this.userPasswordHistoryBean.getUserPasswordHistory(confirmedUser);
307
308                         // Set template to "login"
309                         this.setBaseTemplatePathName(USER_BASE_TEMPLATE_NAME); //NOI18N
310
311                         // Fire event away. Keep this last before return statement.
312                         this.userLoginEvent.fire(new UserLoggedInEvent(confirmedUser));
313
314                         // Clear this bean
315                         this.clear();
316
317                         // All fine
318                         return "login_user"; //NOI18N
319                 } catch (final UserNotFoundException ex) {
320                         // Show JSF message
321                         this.showFacesMessage("form_user_login:userName", "ERROR_USER_NOT_FOUND"); //NOI18N
322                         return ""; //NOI18N
323                 } catch (final UserStatusLockedException ex) {
324                         this.showFacesMessage("form_user_login:userName", "ERROR_USER_STATUS_LOCKED"); //NOI18N
325                         return ""; //NOI18N
326                 } catch (final UserStatusUnconfirmedException ex) {
327                         this.showFacesMessage("form_user_login:userName", "ERROR_USER_STATUS_UNCONFIRMED"); //NOI18N
328                         return ""; //NOI18N
329                 } catch (final UserPasswordMismatchException ex) {
330                         // Show JSF message
331                         this.showFacesMessage("form_user_login:userPassword", "ERROR_USER_PASSWORD_MISMATCH"); //NOI18N
332                         return ""; //NOI18N
333                 }
334         }
335
336         /**
337          * Logout for current user by invalidating the current session.
338          * <p>
339          * @return Outcome (should be redirected)
340          */
341         public String doUserLogout () {
342                 // Is loggedInUser set?
343                 if (this.getLoggedInUser() == null) {
344                         // Throw NPE
345                         throw new NullPointerException("this.loggedInUser is null"); //NOI18N
346                 } else if (this.getLoggedInUser().getUserId() == null) {
347                         // Throw again
348                         throw new NullPointerException("this.loggedInUser.userId is null"); //NOI18N
349                 } else if (this.getLoggedInUser().getUserId() < 1) {
350                         // Invalid user id
351                         throw new IllegalStateException(MessageFormat.format("this.loggedInUser.userId={0} is not valid.", this.getLoggedInUser().getUserId())); //NOI18N
352                 }
353
354                 // Fire event
355                 this.userLogoutEvent.fire(new UserLogoutEvent(this.getLoggedInUser()));
356
357                 // Invalidate session
358                 FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
359
360                 // Unset any user instances
361                 this.setLoggedInUser(null);
362                 this.setBaseTemplatePathName(GUEST_BASE_TEMPLATE_NAME); //NOI18N
363
364                 // Redirect to index
365                 return "index"; //NOI18N
366         }
367
368         @Override
369         public String getBaseTemplatePathName () {
370                 return this.baseTemplatePathName;
371         }
372
373         @Override
374         public void setBaseTemplatePathName (final String baseTemplatePathName) {
375                 this.baseTemplatePathName = baseTemplatePathName;
376         }
377
378         @Override
379         public User getLoggedInUser () {
380                 return this.loggedInUser;
381         }
382
383         @Override
384         public void setLoggedInUser (final User loggedInUser) {
385                 this.loggedInUser = loggedInUser;
386         }
387
388         /**
389          * Getter for current password (clear text)
390          * <p>
391          * @return Current password
392          */
393         public String getUserCurrentPassword () {
394                 return this.userCurrentPassword;
395         }
396
397         /**
398          * Setter for current password (clear text)
399          * <p>
400          * @param userCurrentPassword Current password
401          */
402         public void setUserCurrentPassword (final String userCurrentPassword) {
403                 this.userCurrentPassword = userCurrentPassword;
404         }
405
406         @Override
407         public List<PasswordHistory> getUserPasswordHistory () {
408                 return Collections.unmodifiableList(this.userPasswordHistory);
409         }
410
411         @Override
412         public boolean ifCurrentPasswordMatches () {
413                 // The current password must be set and not empty
414                 if (this.getUserCurrentPassword() == null) {
415                         // Is not set
416                         throw new NullPointerException("this.userCurrentPassword is null"); //NOI18N
417                 } else if (this.getUserCurrentPassword().isEmpty()) {
418                         // Is set empty
419                         throw new IllegalStateException("this.userCurrentPassword is empty."); //NOI18N
420                 }
421
422                 // Create "container"
423                 final LoginContainer container = new UserLoginContainer(this.getLoggedInUser(), this.getUserCurrentPassword());
424
425                 // Now check if it matches
426                 return UserLoginUtils.ifPasswordMatches(container, this.getLoggedInUser());
427         }
428
429         @Override
430         public boolean ifUserMustChangePassword () {
431                 return ((this.isUserLoggedIn()) && (Objects.equals(this.getLoggedInUser().getUserMustChangePassword(), Boolean.TRUE)));
432         }
433
434         @Override
435         public boolean isInvisible () {
436                 // Check on login
437                 if (!this.isUserLoggedIn()) {
438                         // Not logged in!
439                         throw new IllegalStateException("isInvisible() has been invoked for a guest."); //NOI18N
440                 }
441
442                 // Check logged-in first, then invisibility
443                 return Objects.equals(this.getLoggedInUser().getUserProfileMode(), ProfileMode.INVISIBLE);
444         }
445
446         @Override
447         public boolean isPasswordInHistory (final String userPassword) {
448                 // Default is not found
449                 boolean isPasswordInHistory = false;
450
451                 // Init variables
452                 int count = 1;
453                 final int maxEntries = this.getIntegerContextParameter("max_user_password_history"); //NOI18N
454
455                 // Check all passwords
456                 for (final PasswordHistory entry : this.getUserPasswordHistory()) {
457                         // Is password the same?
458                         if (UserLoginUtils.ifPasswordMatches(userPassword, entry.getUserPasswordHistoryUser())) {
459                                 // Yes, found it
460                                 isPasswordInHistory = true;
461                                 break;
462                         } else if (count == maxEntries) {
463                                 // Maximum reached
464                                 break;
465                         }
466
467                         // Count up
468                         count++;
469                 }
470
471                 // Return status
472                 return isPasswordInHistory;
473         }
474
475         @Override
476         public boolean isUserLoggedIn () {
477                 // Compare instance
478                 this.userLoggedIn = ((this.getLoggedInUser() instanceof User) && (Objects.equals(this.getLoggedInUser().getUserAccountStatus(), UserAccountStatus.CONFIRMED)));
479
480                 // Return it
481                 return this.userLoggedIn;
482         }
483
484         /**
485          * Clears this bean
486          */
487         private void clear () {
488                 // Clear all fields
489                 this.setUserCurrentPassword(null);
490                 this.setUserProfileMode(null);
491         }
492
493         /**
494          * Copies given user into the controller
495          * <p>
496          * @param user User instance
497          */
498         private void copyToUser (final User user) {
499                 // Copy all fields:
500                 // - base data
501                 this.setUserId(user.getUserId());
502                 this.setUserName(user.getUserName());
503                 this.setUserProfileMode(user.getUserProfileMode());
504         }
505
506         /**
507          * Updates password history by adding given entry to it as long as it is not
508          * there.
509          * <p>
510          * @param passwordHistory Password history entry
511          */
512         private void updatePasswordHistory (final PasswordHistory passwordHistory) {
513                 if (null == passwordHistory) {
514                         // Throw NPE
515                         throw new NullPointerException("passwordHistory is null"); //NOI18N
516                 } else if (passwordHistory.getUserPasswordHistoryId() == null) {
517                         // Throw NPE again
518                         throw new NullPointerException("passwordHistory.userPasswordHistoryId is null"); //NOI18N
519                 } else if (passwordHistory.getUserPasswordHistoryId() < 1) {
520                         // Invalid id
521                         throw new IllegalArgumentException(MessageFormat.format("passwordHistory.userPasswordHistoryId={0} is not valid.", passwordHistory.getUserPasswordHistoryId())); //NOI18N
522                 }
523
524                 // Is it there?
525                 if (this.userPasswordHistory.contains(passwordHistory)) {
526                         // Excact copy found
527                         return;
528                 }
529
530                 // Check all entries
531                 for (final PasswordHistory entry : this.userPasswordHistory) {
532                         // Is same id number?
533                         if (Objects.equals(entry.getUserPasswordHistoryId(), passwordHistory.getUserPasswordHistoryId())) {
534                                 // Found it
535                                 return;
536                         }
537                 }
538
539                 // Not found, so add it
540                 this.userPasswordHistory.add(passwordHistory);
541         }
542
543 }