ru.mystamps.web.service.SiteServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for ru.mystamps.web.service.SiteServiceImpl.java

Source

/*
 * Copyright (C) 2009-2017 Slava Semushin <slava.semushin@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package ru.mystamps.web.service;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;

import ru.mystamps.web.Db;
import ru.mystamps.web.dao.SuspiciousActivityDao;
import ru.mystamps.web.dao.dto.AddSuspiciousActivityDbDto;
import ru.mystamps.web.support.spring.security.SecurityContextUtils;

@RequiredArgsConstructor
public class SiteServiceImpl implements SiteService {

    // see initiate-suspicious_activities_types-table changeset
    // in src/main/resources/liquibase/initial-state.xml
    public static final String PAGE_NOT_FOUND = "PageNotFound";
    public static final String AUTHENTICATION_FAILED = "AuthenticationFailed";

    // see add-types-for-csrf-tokens-to-suspicious_activities_types-table changeset
    // in src/main/resources/liquibase/version/0.4/2016-02-19--csrf_events.xml
    public static final String MISSING_CSRF_TOKEN = "MissingCsrfToken";
    public static final String INVALID_CSRF_TOKEN = "InvalidCsrfToken";

    private static final Logger LOG = LoggerFactory.getLogger(SiteServiceImpl.class);

    private final SuspiciousActivityDao suspiciousActivities;

    @Override
    @SuppressWarnings("PMD.UseObjectForClearerAPI")
    @Async
    @Transactional
    public void logAboutAbsentPage(String page, String method, Integer userId, String ip, String referer,
            String agent) {

        logEvent(PAGE_NOT_FOUND, page, method, userId, ip, referer, agent, new Date());
    }

    @Override
    @SuppressWarnings("PMD.UseObjectForClearerAPI")
    @Transactional
    public void logAboutFailedAuthentication(String page, String method, Integer userId, String ip, String referer,
            String agent, Date date) {

        logEvent(AUTHENTICATION_FAILED, page, method, userId, ip, referer, agent, date);
    }

    /**
     * @author Sergey Chechenev
     */
    @Override
    @Transactional
    public void logAboutMissingCsrfToken(HttpServletRequest request) {

        logEvent(MISSING_CSRF_TOKEN, request.getRequestURI(), request.getMethod(), SecurityContextUtils.getUserId(),
                request.getRemoteAddr(), request.getHeader("referer"), request.getHeader("user-agent"), new Date());

    }

    /**
     * @author Sergey Chechenev
     */
    @Override
    @Transactional
    public void logAboutInvalidCsrfToken(HttpServletRequest request) {

        logEvent(INVALID_CSRF_TOKEN, request.getRequestURI(), request.getMethod(), SecurityContextUtils.getUserId(),
                request.getRemoteAddr(), request.getHeader("referer"), request.getHeader("user-agent"), new Date());

    }

    // protected for using in unit tests
    @SuppressWarnings({ "PMD.UseObjectForClearerAPI", "checkstyle:parameternumber" })
    protected void logEvent(String type, String page, String method, Integer userId, String ip, String referer,
            String agent, Date date) {

        Validate.isTrue(type != null, "Type of suspicious activity must be non null");
        Validate.isTrue(page != null, "Page must be non null");

        AddSuspiciousActivityDbDto activity = new AddSuspiciousActivityDbDto();

        activity.setType(type);
        activity.setOccurredAt(date == null ? new Date() : date);
        activity.setPage(abbreviatePage(page));
        activity.setMethod(abbreviateMethod(method));
        activity.setUserId(userId);
        activity.setIp(StringUtils.defaultString(ip));
        activity.setRefererPage(StringUtils.stripToNull(abbreviateRefererPage(referer)));
        activity.setUserAgent(StringUtils.stripToNull(abbreviateUserAgent(agent)));

        suspiciousActivities.add(activity);
    }

    /**
     * Abbreviate name of HTTP method.
     * @param method name of HTTP method
     * @return name of the method as-is or its abbreviation with three points at the end
     * @author Aleksandr Zorin
     */
    private static String abbreviateMethod(String method) {
        return abbreviateIfLengthGreaterThan(method, Db.SuspiciousActivity.METHOD_LENGTH, "method");
    }

    private static String abbreviatePage(String page) {
        return abbreviateIfLengthGreaterThan(page, Db.SuspiciousActivity.PAGE_URL_LENGTH, "page");
    }

    private static String abbreviateRefererPage(String referer) {
        return abbreviateIfLengthGreaterThan(referer, Db.SuspiciousActivity.REFERER_PAGE_LENGTH, "referer_page");
    }

    private static String abbreviateUserAgent(String agent) {
        return abbreviateIfLengthGreaterThan(agent, Db.SuspiciousActivity.USER_AGENT_LENGTH, "user_agent");
    }

    // CheckStyle: ignore LineLength for next 1 lines
    private static String abbreviateIfLengthGreaterThan(String text, int maxLength, String fieldName) {
        if (text == null || text.length() <= maxLength) {
            return text;
        }

        // TODO(security): fix possible log injection
        LOG.warn("Length of value for '{}' field ({}) exceeds max field size ({}): '{}'", fieldName, text.length(),
                maxLength, text);

        return StringUtils.abbreviate(text, maxLength);
    }

}