fr.itldev.koya.services.impl.UserServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for fr.itldev.koya.services.impl.UserServiceImpl.java

Source

/**
 * Koya is an alfresco module that provides a corporate orientated dataroom.
 *
 * Copyright (C) Itl Developpement 2014
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see `<http://www.gnu.org/licenses/>`.
 */
package fr.itldev.koya.services.impl;

import fr.itldev.koya.model.impl.Company;
import fr.itldev.koya.model.impl.Notification;
import fr.itldev.koya.model.impl.Preferences;
import fr.itldev.koya.model.impl.Space;
import fr.itldev.koya.model.impl.User;
import fr.itldev.koya.model.json.AuthTicket;
import fr.itldev.koya.services.UserService;
import fr.itldev.koya.services.exceptions.AlfrescoServiceException;
import fr.itldev.koya.services.exceptions.KoyaErrorCodes;
import static fr.itldev.koya.services.impl.AlfrescoRestService.fromJSON;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.log4j.Logger;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

public class UserServiceImpl extends AlfrescoRestService implements UserService, BeanFactoryAware {

    private Logger logger = Logger.getLogger(this.getClass());

    private static final String REST_GET_LOGIN = "/s/api/login.json?u={username}&pw={password}";
    private static final String REST_POST_PERSONFROMMAIL = "/s/fr/itldev/koya/user/getbyauthkey?alf_ticket={alf_ticket}";
    private static final String REST_DEL_LOGOUT = "/s/api/login/ticket/{ticket}";
    private static final String REST_POST_MODIFYDETAILS = "/s/fr/itldev/koya/user/modifydetails";
    private static final String REST_GET_FINDUSERS = "/s/fr/itldev/koya/user/find?"
            + "query={query}&maxResults={maxresults}&companyName={companyName}&roleFilter={roleFilter}";
    private static final String REST_GET_CHANGEPASSWORD = "/s/fr/itldev/koya/user/changepassword/{oldpwd}/{newpwd}";
    private static final String REST_GET_GROUPS = "/s/fr/itldev/koya/user/groups";

    //===== Preferences
    private static final String REST_GET_PREFERENCES = "/s/api/people/{userid}/preferences";
    private static final String REST_POST_PREFERENCES = "/s/api/people/{userid}/preferences";
    private static final String REST_DELETE_PREFERENCES = "/s/api/people/{userid}/preferences?pf={preferencefilter?}";

    //====== Notifications
    private static final String REST_GET_EMAILNOTIFICATION = "/s/fr/itldev/koya/user/emailnotification/{userName}";
    private static final String REST_GET_EMAILNOTIFICATION_ENABLE = "/s/fr/itldev/koya/user/emailnotification/{userName}/{enable}";

    //====== reset password BPM
    private static final String REST_POST_RESET_PASSWORD_REQUEST = "/s/fr/itldev/koya/resetpassword/request";
    private static final String REST_POST_RESET_PASSWORD_VALIDATION = "/s/fr/itldev/koya/resetpassword/validation";

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory bf) throws BeansException {
        this.beanFactory = bf;
    }

    /**
     * Authenticates user with authentication key that could be his login or
     * email.
     *
     *
     * TODO give md5 or other secured password instead of clear.
     *
     * @param authKey
     * @param password
     * @return
     * @throws fr.itldev.koya.services.exceptions.AlfrescoServiceException
     */
    @Override
    public User login(String authKey, String password) throws RestClientException, AlfrescoServiceException {

        //call rest ticket
        AuthTicket ticket = fromJSON(new TypeReference<AuthTicket>() {
        }, getTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_LOGIN, String.class, authKey, password));
        //Get User Object
        Map emailPostWrapper = new HashMap();
        emailPostWrapper.put("authKey", authKey);
        User user = fromJSON(new TypeReference<User>() {
        }, getTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_PERSONFROMMAIL, emailPostWrapper,
                String.class, ticket));

        //Authentication ticket integration
        user.setTicketAlfresco(ticket.toString());
        try {
            //set users authenticated rest template
            user.setRestTemplate(getAuthenticatedRestTemplate(user.getUserName(), password));
        } catch (MalformedURLException ex) {
            throw new AlfrescoServiceException(ex.toString());
        }
        //load users rest prefrences
        loadPreferences(user);
        //
        user.setPassword(password);
        return user;
    }

    @Override
    public Boolean logout(User user) throws AlfrescoServiceException {
        try {
            user.getRestTemplate().delete(getAlfrescoServerUrl() + REST_DEL_LOGOUT, user.getTicketAlfresco());
        } catch (RestClientException rce) {
            throw new AlfrescoServiceException(rce.getMessage(), KoyaErrorCodes.CANNOT_LOGOUT_USER);
        }

        //TODO treat returns
        return null;

    }

    @Override
    public void createUser(User userAdmin, User toCreate) {
        //exception if doesn't work
    }

    /**
     * Authenticated RestTemplate Factory.
     *
     * @return
     */
    private RestTemplate getAuthenticatedRestTemplate(String login, String password) throws MalformedURLException {
        URL url = new URL(getAlfrescoServerUrl());

        RestTemplate userRestTemplate = new RestClient(login, password, url.getHost(), url.getPort(),
                url.getProtocol());
        List<HttpMessageConverter<?>> msgConverters = new ArrayList<>();
        msgConverters.add((HttpMessageConverter<?>) beanFactory.getBean("stringHttpMessageConverter"));
        msgConverters.add((HttpMessageConverter<?>) beanFactory.getBean("jsonHttpMessageConverter"));
        msgConverters.add((HttpMessageConverter<?>) beanFactory.getBean("formHttpMessageConverter"));
        userRestTemplate.setMessageConverters(msgConverters);
        userRestTemplate.setErrorHandler((ResponseErrorHandler) beanFactory.getBean("alfrescoRestErrorHandler"));

        return userRestTemplate;
    }

    /**
     * Updates users preferences from alfresco server. Erases unsaved local
     * preferences.
     *
     * @param user
     */
    @Override
    public void loadPreferences(User user) {
        loadPreferences(user, user);
    }

    @Override
    public void loadPreferences(User userLog, User userToGetPrefs) {
        Preferences preferences = fromJSON(new TypeReference<Preferences>() {
        }, userLog.getRestTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_PREFERENCES, String.class,
                userToGetPrefs.getUserName()));
        userToGetPrefs.setPreferences(preferences);
    }

    /**
     * Writes local preferences to alfresco server.
     *
     * @param user
     * @throws fr.itldev.koya.services.exceptions.AlfrescoServiceException
     */
    @Override
    public void commitPreferences(User user) throws AlfrescoServiceException {
        commitPreferences(user, user);
    }

    @Override
    public void commitPreferences(User userLog, User userToCommitPrefs) throws AlfrescoServiceException {

        if (userToCommitPrefs.getPreferences() != null) {
            // 1 - send new and modified keys
            userLog.getRestTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_PREFERENCES,
                    userToCommitPrefs.getPreferences(), Preferences.class, userToCommitPrefs.getUserName());

            // 2 - updates preferences from server
            Preferences prefsToCommit = userToCommitPrefs.getPreferences();
            loadPreferences(userLog, userToCommitPrefs);

            // 3 - if less preferences to commit than updates --> some keys have to be deleted.
            if (prefsToCommit.size() < userToCommitPrefs.getPreferences().size()) {

                String deleteFilter = "";
                String sep = "";
                for (String k : userToCommitPrefs.getPreferences().keySet()) {
                    if (!prefsToCommit.keySet().contains(k)) {
                        deleteFilter += sep + k;
                        sep = ",";
                    }
                }
                userLog.getRestTemplate().delete(getAlfrescoServerUrl() + REST_DELETE_PREFERENCES,
                        userToCommitPrefs.getUserName(), deleteFilter);
                loadPreferences(userLog, userToCommitPrefs);
            }

        } else {
            throw new AlfrescoServiceException("No user preference to commit", 0);
        }

    }

    @Override
    public void commitProperties(User user) throws AlfrescoServiceException {
        commitProperties(user, user);
    }

    @Override
    public void commitProperties(User userLog, User userToCommitProps) throws AlfrescoServiceException {
        userLog.getRestTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_MODIFYDETAILS, userToCommitProps,
                String.class);
    }

    @Override
    public void changePassword(User userLog, String oldPassword, String newPassword)
            throws AlfrescoServiceException, MalformedURLException {
        userLog.getRestTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_CHANGEPASSWORD, String.class,
                oldPassword, newPassword);

        userLog.setRestTemplate(getAuthenticatedRestTemplate(userLog.getUserName(), newPassword));

    }

    /**
     * find users list wich first/last name or email starts with query. Return
     * list limitated by maxResults.
     *
     * if company is not null limit results to company scope. rolesFilter can
     * refine results in this company context (not taken in account if no
     * company is set)
     *
     * @param userLog
     * @param query
     * @param maxResults
     * @param company
     * @param rolesFilter
     * @return
     * @throws AlfrescoServiceException
     */
    @Override
    public List<User> find(User userLog, String query, Integer maxResults, Company company,
            List<String> rolesFilter) throws AlfrescoServiceException {

        String companyName = "";
        String roles = "";

        if (company != null) {
            companyName = company.getName();
        }
        if (rolesFilter != null && rolesFilter.size() > 0) {
            String sep = "";
            for (String r : rolesFilter) {
                roles += sep + r;
                sep = ",";
            }
        }

        return fromJSON(new TypeReference<List<User>>() {
        }, userLog.getRestTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_FINDUSERS, String.class, query,
                maxResults, companyName, roles));

    }

    @Override
    public List<Notification> getNotifications(User userLog) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        //cf alfresco activity service
    }

    /**
     * Get user Object from email.
     *
     * @param user
     * @param email
     * @return
     * @throws AlfrescoServiceException
     */
    @Override
    public User getUserFromEmail(User user, String email) throws AlfrescoServiceException {
        Map emailPostWrapper = new HashMap();
        emailPostWrapper.put("authKey", email);
        return fromJSON(new TypeReference<User>() {
        }, getTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_PERSONFROMMAIL, emailPostWrapper,
                String.class, user.getTicketAlfresco()));
    }

    @Override
    public User getUserFromEmailFailProof(User user, String email) {
        Map emailPostWrapper = new HashMap();
        emailPostWrapper.put("authKey", email);
        emailPostWrapper.put("failProof", true);
        try {
            return fromJSON(new TypeReference<User>() {
            }, getTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_PERSONFROMMAIL, emailPostWrapper,
                    String.class, user.getTicketAlfresco()));
        } catch (RestClientException e) {
            return null;
        }
    }

    private class RestClient extends RestTemplate {
        //        http://forum.spring.io/forum/spring-projects/web/114029-preemptive-basic-authentication-with-resttemplate

        public RestClient(String username, String password, String host, int port, String protocol) {
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(new AuthScope(null, -1),
                    new UsernamePasswordCredentials(username, password));
            HttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();

            ContextAwareHttpComponentsClientHttpRequestFactory customFactory = new ContextAwareHttpComponentsClientHttpRequestFactory(
                    httpClient);
            HttpHost targetHost = new HttpHost(host, port, protocol);

            // Create AuthCache instance
            AuthCache authCache = new BasicAuthCache();
            authCache.put(targetHost, new BasicScheme());

            // Add AuthCache to the execution context
            BasicHttpContext localContext = new BasicHttpContext();
            localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

            customFactory.setHttpContext(localContext);

            setRequestFactory(customFactory);
        }
    }

    private class ContextAwareHttpComponentsClientHttpRequestFactory
            extends HttpComponentsClientHttpRequestFactory {

        private HttpContext httpContext;

        public ContextAwareHttpComponentsClientHttpRequestFactory(HttpClient httpClient) {
            super(httpClient);
        }

        @Override
        protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
            //Ignoring the URI and method.
            return httpContext;
        }

        public void setHttpContext(HttpContext httpContext) {
            this.httpContext = httpContext;
        }
    }

    @Override
    public void setEmailNotification(User user, boolean notify) throws AlfrescoServiceException {
        user.getRestTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_EMAILNOTIFICATION_ENABLE,
                Boolean.class, user.getUserName(), notify);
    }

    @Override
    public Boolean getEmailNotification(User user) throws AlfrescoServiceException {
        return user.getRestTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_EMAILNOTIFICATION,
                Boolean.class, user.getUserName());
    }

    /**
     * Send Reset password request to alfresco server.
     *
     *
     * @param userEmail
     * @param resetUrl
     * @throws AlfrescoServiceException
     */
    @Override
    public void sendResetPasswordRequest(String userEmail, String resetUrl) throws AlfrescoServiceException {
        Map<String, String> params = new HashMap<>();
        params.put("userEmail", userEmail);
        params.put("resetUrl", resetUrl);

        getTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_RESET_PASSWORD_REQUEST, params,
                String.class);
    }

    /**
     * Validate password modification in reset password process.
     *
     * Authenticated by resetId + resetTicket.
     *
     * @param resetId
     * @param resetTicket
     * @param newPassword
     * @throws AlfrescoServiceException
     */
    @Override
    public void validateNewPasswordfromResetProcess(String resetId, String resetTicket, String newPassword)
            throws AlfrescoServiceException {

        Map<String, String> params = new HashMap<>();
        params.put("resetId", resetId);
        params.put("resetTicket", resetTicket);
        params.put("newPassword", newPassword);
        getTemplate().postForObject(getAlfrescoServerUrl() + REST_POST_RESET_PASSWORD_VALIDATION, params,
                String.class);
    }

    @Override
    public List<String> getGroups(User user) {

        return fromJSON(new TypeReference<List<String>>() {
        }, user.getRestTemplate().getForObject(getAlfrescoServerUrl() + REST_GET_GROUPS, String.class));

    }
}