org.apache.rave.portal.service.impl.DefaultUserService.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.rave.portal.service.impl.DefaultUserService.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.rave.portal.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.apache.rave.model.PageType;
import org.apache.rave.model.Person;
import org.apache.rave.model.User;
import org.apache.rave.rest.model.SearchResult;
import org.apache.rave.portal.repository.CategoryRepository;
import org.apache.rave.portal.repository.PageRepository;
import org.apache.rave.portal.repository.PageTemplateRepository;
import org.apache.rave.portal.repository.PersonRepository;
import org.apache.rave.portal.repository.UserRepository;
import org.apache.rave.portal.repository.WidgetRepository;
import org.apache.rave.portal.service.EmailService;
import org.apache.rave.portal.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Service(value = "userService")
public class DefaultUserService implements UserService {
    private static final Logger log = LoggerFactory.getLogger(DefaultUserService.class);

    private final UserRepository userRepository;
    private final PageRepository pageRepository;
    private final PageTemplateRepository pageTemplateRepository;
    private final WidgetRepository widgetRepository;
    private final CategoryRepository categoryRepository;
    private final PersonRepository personRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private EmailService emailService;

    @Value("${portal.mail.passwordservice.subject}")
    private String passwordReminderSubject;

    @Value("${portal.mail.passwordservice.template}")
    private String passwordReminderTemplate;

    @Value("${portal.mail.username.subject}")
    private String userNameReminderSubject;

    @Value("${portal.mail.username.template}")
    private String userNameReminderTemplate;

    @Value("${portal.mail.service.baseurl}")
    private String baseUrl;

    @Value("${portal.user.account.admin.subject}")
    private String userAccountApprovalSubject;

    @Value("${portal.user.account.admin.template}")
    private String userAccountApprovalTemplate;

    @Value("${portal.user.account.needapproval}")
    private boolean userAccountApproval;

    @Value("${portal.user.account.admin.email}")
    private String approvalAdminEmail;

    @Value("${portal.mail.service.loginpage}")
    private String loginUrl;

    @Autowired
    public DefaultUserService(PageRepository pageRepository, UserRepository userRepository,
            WidgetRepository widgetRepository, PageTemplateRepository pageTemplateRepository,
            CategoryRepository categoryRepository, PersonRepository personRepository) {
        this.userRepository = userRepository;
        this.pageRepository = pageRepository;
        this.widgetRepository = widgetRepository;
        this.pageTemplateRepository = pageTemplateRepository;
        this.categoryRepository = categoryRepository;
        this.personRepository = personRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
        log.debug("loadUserByUsername called with: {}", username);
        final User user = userRepository.getByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User with username '" + username + "' was not found!");
        }
        return user;
    }

    @Override
    public User getAuthenticatedUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication != null && authentication.getPrincipal() instanceof User) {
            return (User) authentication.getPrincipal();
        } else {
            throw new SecurityException("Could not get the authenticated user!");
        }
    }

    @Override
    public void setAuthenticatedUser(String userId) {
        final User user = userRepository.get(userId);
        if (user == null) {
            throw new UsernameNotFoundException("User with id '" + userId + "' was not found!");
        }
        SecurityContext securityContext = createContext(user);
        SecurityContextHolder.setContext(securityContext);
    }

    @Override
    public void clearAuthenticatedUser() {
        SecurityContextHolder.clearContext();
    }

    private SecurityContext createContext(final User user) {
        SecurityContext securityContext = new SecurityContextImpl();
        securityContext.setAuthentication(new AbstractAuthenticationToken(user.getAuthorities()) {
            private static final long serialVersionUID = 1L;

            @Override
            public Object getCredentials() {
                return "N/A";
            }

            @Override
            public Object getPrincipal() {
                return user;
            }

            @Override
            public boolean isAuthenticated() {
                return true;
            }
        });
        return securityContext;
    }

    @Override
    @Transactional
    public void registerNewUser(User user) {
        if (userAccountApproval) {
            user.setEnabled(false);
        }
        User managedUser = userRepository.save(user);
        pageRepository.createPageForUser(managedUser,
                pageTemplateRepository.getDefaultPage(PageType.PERSON_PROFILE.toString()));
        if (userAccountApproval && !approvalAdminEmail.isEmpty()) {
            Map<String, Object> templateData = new HashMap<String, Object>();
            templateData.put("user", user);
            templateData.put("portalUrl", loginUrl);
            emailService.sendEmail(approvalAdminEmail, userAccountApprovalSubject, userAccountApprovalTemplate,
                    templateData);
        }
    }

    @Override
    public User getUserById(String id) {
        return userRepository.get(id);
    }

    @Override
    public User getUserByUsername(String userName) {
        return userRepository.getByUsername(userName);
    }

    @Override
    public User getUserByEmail(String userEmail) {
        return userRepository.getByUserEmail(userEmail);
    }

    @Override
    public User getUserByOpenId(String openId) {
        return userRepository.getByOpenId(openId);
    }

    @Override
    @Transactional
    public void updateUserProfile(User user) {
        userRepository.save(user);
    }

    @Override
    public SearchResult<User> getAll() {
        final int count = userRepository.getCountAll();
        final List<User> users = userRepository.getAll();
        return new SearchResult<User>(users, count);
    }

    @Override
    public SearchResult<User> getLimitedList(int offset, int pageSize) {
        final int count = userRepository.getCountAll();
        final List<User> users = userRepository.getLimitedList(offset, pageSize);
        final SearchResult<User> searchResult = new SearchResult<User>(users, count);
        searchResult.setOffset(offset);
        searchResult.setPageSize(pageSize);
        return searchResult;
    }

    @Override
    public SearchResult<Person> getLimitedListOfPersons(int offset, int pageSize) {
        SearchResult<User> users = getLimitedList(offset, pageSize);
        int count = users.getTotalResults();
        List<Person> people = new ArrayList<Person>();
        Person person = null;
        for (User user : users.getResultSet()) {
            person = user.toPerson();
            person.setId(user.getId());
            people.add(person);
        }
        return new SearchResult<Person>(people, count);
    }

    @Override
    public SearchResult<User> getUsersByFreeTextSearch(String searchTerm, int offset, int pageSize) {
        final int count = userRepository.getCountByUsernameOrEmail(searchTerm);
        final List<User> users = userRepository.findByUsernameOrEmail(searchTerm, offset, pageSize);
        final SearchResult<User> searchResult = new SearchResult<User>(users, count);
        searchResult.setOffset(offset);
        searchResult.setPageSize(pageSize);
        return searchResult;
    }

    @Override
    public SearchResult<Person> getPersonsByFreeTextSearch(String searchTerm, int offset, int pageSize) {
        SearchResult<User> users = getUsersByFreeTextSearch(searchTerm, offset, pageSize);
        int count = users.getTotalResults();
        List<Person> people = new ArrayList<Person>();
        Person person = null;
        for (User user : users.getResultSet()) {
            person = user.toPerson();
            person.setId(user.getId());
            people.add(person);
        }
        return new SearchResult<Person>(people, count);
    }

    @Override
    @Transactional
    // TODO RAVE-300: add security check that is is called by admin or the user itself
    public void deleteUser(String userId) {
        log.info("about to delete userId: " + userId);
        User user = userRepository.get(userId);
        if (user == null) {
            log.warn("unable to find userId " + userId + " to delete");
            return;
        }

        final String username = user.getUsername();

        // delete all User type pages
        int numDeletedPages = pageRepository.deletePages(userId, PageType.USER.toString());
        // delete all person pages
        int numDeletedPersonPages = pageRepository.deletePages(userId, PageType.PERSON_PROFILE.toString());
        // delete all the widget comments
        int numWidgetComments = widgetRepository.deleteAllWidgetComments(userId);
        // delete all the widget ratings
        int numWidgetRatings = widgetRepository.deleteAllWidgetRatings(userId);
        // unassign the user from any widgets where they were the owner
        int numWidgetsOwned = widgetRepository.unassignWidgetOwner(userId);
        // unassign the user from any category records they created or modified
        int numCategoriesTouched = categoryRepository.removeFromCreatedOrModifiedFields(userId);
        // remove any person associations created with other users
        int numAssociationsRemoved = personRepository.removeAllFriendsAndRequests(userId);

        // finally delete the user
        userRepository.delete(user);
        log.info("Deleted user [" + userId + ',' + username + "] - numPages: " + numDeletedPages
                + ", numPersonPages:" + numDeletedPersonPages + ", numWidgetComments: " + numWidgetComments
                + ", numWidgetRatings: " + numWidgetRatings + ", numWidgetsOwned: " + numWidgetsOwned
                + ", numCategoriesTouched:" + numCategoriesTouched + ", numAssociationRemoved:"
                + numAssociationsRemoved);
    }

    @Override
    public List<Person> getAllByAddedWidget(String widgetId) {
        List<Person> persons = new ArrayList<Person>();
        List<User> users = userRepository.getAllByAddedWidget(widgetId);
        for (User u : users) {
            persons.add(u.toPerson());
        }
        return persons;
    }

    @Override
    public void updatePassword(User newUser) {
        log.debug("Changing password  for user {}", newUser);
        User user = userRepository.getByForgotPasswordHash(newUser.getForgotPasswordHash());
        if (user == null) {
            throw new IllegalArgumentException(
                    "Could not find user for forgotPasswordHash " + newUser.getForgotPasswordHash());
        }
        String saltedHashedPassword = passwordEncoder.encode(newUser.getPassword());
        user.setPassword(saltedHashedPassword);
        // reset password hash and time
        user.setForgotPasswordHash(null);
        user.setForgotPasswordTime(null);
        userRepository.save(user);

    }

    @Override
    public void sendUserNameReminder(User newUser) {
        log.debug("Calling send username  {}", newUser);
        User user = userRepository.getByUserEmail(newUser.getEmail());
        if (user == null) {
            throw new IllegalArgumentException("Could not find user for email " + newUser.getEmail());
        }
        String to = user.getUsername() + " <" + user.getEmail() + '>';
        Map<String, Object> templateData = new HashMap<String, Object>();
        templateData.put("user", user);
        emailService.sendEmail(to, userNameReminderSubject, userNameReminderTemplate, templateData);

    }

    @Override
    public void sendPasswordReminder(User newUser) {
        log.debug("Calling send password change link for user {}", newUser);
        User user = userRepository.getByUserEmail(newUser.getEmail());
        if (user == null) {
            throw new IllegalArgumentException("Could not find user for email " + newUser.getEmail());
        }
        // create user hash:
        String input = user.getEmail() + user.getUsername() + String.valueOf(user.getId()) + System.nanoTime();
        // hash needs to be URL friendly:
        String safeString = new String(Base64.encode(passwordEncoder.encode(input).getBytes()));
        String hashedInput = safeString.replaceAll("[/=]", "A");
        user.setForgotPasswordHash(hashedInput);
        user.setForgotPasswordTime(Calendar.getInstance().getTime());
        userRepository.save(user);
        String to = user.getUsername() + " <" + user.getEmail() + '>';
        Map<String, Object> templateData = new HashMap<String, Object>();
        templateData.put("user", user);
        templateData.put("reminderUrl", baseUrl + hashedInput);
        emailService.sendEmail(to, passwordReminderSubject, passwordReminderTemplate, templateData);
    }

    @Override
    public boolean isValidReminderRequest(String forgotPasswordHash, int nrOfMinutesValid) {
        if (StringUtils.isBlank(forgotPasswordHash)) {
            return false;
        }

        User userForHash = userRepository.getByForgotPasswordHash(forgotPasswordHash);
        if (userForHash == null) {
            return false;
        }
        Date requestTime = userForHash.getForgotPasswordTime();
        Calendar expiredDate = Calendar.getInstance();
        expiredDate.add(Calendar.MINUTE, nrOfMinutesValid);

        if (requestTime == null || requestTime.after(expiredDate.getTime())) {
            // reset,  this is invalid state
            userForHash.setForgotPasswordHash(null);
            userForHash.setForgotPasswordTime(null);
            userRepository.save(userForHash);
            return false;
        }
        return true;
    }

    @Override
    @Transactional
    public boolean addFriend(String friendUsername, String username) {
        return personRepository.addFriend(friendUsername, username);
    }

    @Override
    @Transactional
    public void removeFriend(String friendUsername, String username) {
        personRepository.removeFriend(friendUsername, username);
    }

    @Override
    public HashMap<String, List<Person>> getFriendsAndRequests(String username) {
        return personRepository.findFriendsAndRequests(username);
    }

    @Override
    public List<Person> getFriendRequestsReceived(String username) {
        return personRepository.findFriendRequestsReceived(username);
    }

    @Override
    @Transactional
    public boolean acceptFriendRequest(String friendUsername, String username) {
        return personRepository.acceptFriendRequest(friendUsername, username);
    }

    @Override
    public UserDetails loadUserDetails(OpenIDAuthenticationToken token) throws UsernameNotFoundException {
        final String openId = token.getIdentityUrl();
        User user = this.getUserByOpenId(openId);
        if (user == null) {
            log.info("Open ID User with URL " + openId + " was not found!");
            throw new UsernameNotFoundException("Open ID User with URL " + openId + " was not found!");
        }
        return user;
    }
}