package fi.otavanopisto.muikku.auth; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.enterprise.event.Event; import javax.faces.context.FacesContext; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.LocaleUtils; import org.apache.commons.lang3.StringUtils; import fi.otavanopisto.muikku.auth.AuthenticationResult.ConflictReason; import fi.otavanopisto.muikku.auth.AuthenticationResult.Status; import fi.otavanopisto.muikku.events.LoginEvent; import fi.otavanopisto.muikku.model.base.SchoolDataSource; import fi.otavanopisto.muikku.model.security.AuthSource; import fi.otavanopisto.muikku.model.security.AuthSourceSetting; import fi.otavanopisto.muikku.model.security.UserIdentification; import fi.otavanopisto.muikku.model.users.UserEntity; import fi.otavanopisto.muikku.model.users.UserSchoolDataIdentifier; import fi.otavanopisto.muikku.schooldata.SchoolDataBridgeSessionController; import fi.otavanopisto.muikku.schooldata.SchoolDataController; import fi.otavanopisto.muikku.schooldata.UserSchoolDataController; import fi.otavanopisto.muikku.schooldata.entity.User; import fi.otavanopisto.muikku.session.local.LocalSession; import fi.otavanopisto.muikku.session.local.LocalSessionController; import fi.otavanopisto.muikku.users.UserEntityController; import fi.otavanopisto.muikku.users.UserSchoolDataIdentifierController; public abstract class AbstractAuthenticationStrategy implements AuthenticationProvider { @Inject private Logger logger; @Inject @LocalSession private LocalSessionController sessionController; @Inject private AuthSourceController authSourceController; @Inject private UserIdentificationController userIdentificationController; @Inject private UserEntityController userEntityController; @Inject private SchoolDataController schoolDataController; @Inject private UserSchoolDataController userSchoolDataController; @Inject private UserSchoolDataIdentifierController userSchoolDataIdentifierController; @Inject private SchoolDataBridgeSessionController schoolDataBridgeSessionController; @Inject private Event<LoginEvent> userLoggedInEvent; protected String getFirstRequestParameter(Map<String, String[]> requestParameters, String key) { String[] value = requestParameters.get(key); if (value != null && value.length == 1) { return value[0]; } return null; } protected String getAuthSourceSetting(AuthSource authSource, String key) { AuthSourceSetting authSourceSetting = authSourceController.findAuthSourceSettingsByKey(authSource, key); if (authSourceSetting != null) { return authSourceSetting.getValue(); } return null; } protected AuthenticationResult processLogin(AuthSource authSource, Map<String, String[]> requestParameters, String externalId, List<String> emails, String firstName, String lastName) { if ((emails == null) || (emails.isEmpty())) { return new AuthenticationResult(Status.NO_EMAIL); } Collection<UserEntity> emailUsers = userEntityController.listUserEntitiesByEmails(emails); if (emailUsers.size() > 1) { return new AuthenticationResult(Status.CONFLICT, ConflictReason.SEVERAL_USERS_BY_EMAILS); } UserEntity emailUser = emailUsers.size() == 1 ? emailUsers.iterator().next() : null; boolean newAccount = false; User activeUser = null; UserIdentification userIdentification = userIdentificationController.findUserIdentificationByAuthSourceAndExternalId(authSource, externalId); if (userIdentification != null) { // User has identified by this auth source before if (emailUser != null && !emailUser.getId().equals(userIdentification.getUser().getId())) { return new AuthenticationResult(Status.CONFLICT, ConflictReason.EMAIL_BELONGS_TO_ANOTHER_USER); } } else { // User has not used this auth source before if (emailUser != null) { // But has existing user in the system, so we attach the identification into the same user userIdentification = userIdentificationController.createUserIdentification(emailUser, authSource, externalId); } else { List<User> users = null; // If user can be found from datasources by emails, we just attach those users to new entity schoolDataBridgeSessionController.startSystemSession(); try { users = userSchoolDataController.listUsersByEmails(emails); } finally { schoolDataBridgeSessionController.endSystemSession(); } UserEntity userEntity = null; for (User user : users) { UserSchoolDataIdentifier userSchoolDataIdentifier = userSchoolDataIdentifierController.findUserSchoolDataIdentifierByDataSourceAndIdentifier( user.getSchoolDataSource(), user.getIdentifier()); if (userSchoolDataIdentifier != null) { if (userEntity == null) { userEntity = userSchoolDataIdentifier.getUserEntity(); } else if (!userEntity.getId().equals(userSchoolDataIdentifier.getUserEntity().getId())) { logger.severe(String.format("User %s.%s points to multiple UserEntity instances", user.getSchoolDataSource(), user.getIdentifier())); return new AuthenticationResult(Status.CONFLICT, ConflictReason.SEVERAL_USERS_BY_EMAILS); } } } if (userEntity == null) { logger.severe(String.format("Unable to resolve UserEntity for %s", StringUtils.join(emails, ','))); return new AuthenticationResult(Status.NO_EMAIL); } userIdentification = userIdentificationController.createUserIdentification(userEntity, authSource, externalId); newAccount = true; } } if (activeUser == null) { activeUser = userSchoolDataController.findActiveUser(userIdentification.getUser().getDefaultSchoolDataSource(), userIdentification.getUser().getDefaultIdentifier()); if (activeUser == null) { activeUser = userSchoolDataController.listUsersByEmails(emails).get(0); } } if (activeUser == null) { logger.severe(String.format("Active user could not be found")); return new AuthenticationResult(AuthenticationResult.Status.ERROR); } return login(userIdentification, activeUser, newAccount); } private AuthenticationResult login(UserIdentification userIdentification, User user, boolean newAccount) { UserEntity userEntity = userIdentification.getUser(); UserEntity loggedUser = sessionController.getLoggedUserEntity(); if ((loggedUser == null) || loggedUser.getId().equals(userEntity.getId())) { Locale locale = null; if (StringUtils.isNotBlank(userEntity.getLocale())) { try { locale = LocaleUtils.toLocale(userEntity.getLocale()); } catch (Exception e) { logger.log(Level.SEVERE, String.format("Failed to parse locale %s for user entity %d", loggedUser.getLocale(), loggedUser.getId())); } } if (locale == null) { locale = new Locale("fi"); } sessionController.setLocale(locale); SchoolDataSource schoolDataSource = schoolDataController.findSchoolDataSource(user.getSchoolDataSource()); userEntityController.updateDefaultSchoolDataSource(userEntity, schoolDataSource); userEntityController.updateDefaultIdentifier(userEntity, user.getIdentifier()); sessionController.login(schoolDataSource.getIdentifier(), user.getIdentifier()); userEntityController.updateLastLogin(userEntity); HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); userLoggedInEvent.fire(new LoginEvent(userEntity.getId(), sessionController.getLoggedUser(), this, req.getRemoteAddr())); return new AuthenticationResult(newAccount ? Status.NEW_ACCOUNT : Status.LOGIN); } else { return new AuthenticationResult(Status.CONFLICT, ConflictReason.LOGGED_IN_AS_DIFFERENT_USER); } } }