org.codice.ddf.admin.insecure.defaults.service.DefaultUsersDeletionScheduler.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.admin.insecure.defaults.service.DefaultUsersDeletionScheduler.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>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 Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.ddf.admin.insecure.defaults.service;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collection;
import java.util.stream.Stream;
import org.apache.camel.CamelContext;
import org.apache.camel.ServiceStatus;
import org.apache.camel.builder.RouteBuilder;
import org.apache.commons.lang.StringUtils;
import org.apache.karaf.jaas.modules.BackingEngine;
import org.apache.karaf.jaas.modules.BackingEngineFactory;
import org.codice.ddf.configuration.AbsolutePathResolver;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultUsersDeletionScheduler {

    private static Path usersPropertiesFilePath = Paths
            .get(new AbsolutePathResolver("etc/users.properties").getPath());
    private static Path tempTimestampFilePath = Paths
            .get(new AbsolutePathResolver("data/tmp/timestamp.bin").getPath());
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUsersDeletionScheduler.class);
    private static final String ROUTE_ID = "deletionJob";
    private final CamelContext context;

    public DefaultUsersDeletionScheduler(CamelContext camelContext) {
        this.context = camelContext;
    }

    public boolean scheduleDeletion() {
        String cron = getCronOrDelete();
        if (cron == null) {
            return false;
        }
        if (context != null && context.getRouteStatus(ROUTE_ID) != ServiceStatus.Started) {
            try {
                RouteBuilder builder = new RouteBuilder() {
                    @Override
                    public void configure() throws Exception {
                        fromF("quartz2://scheduler/deletionTimer?cron=%s", cron).routeId(ROUTE_ID)
                                .bean(DefaultUsersDeletionScheduler.class, "removeDefaultUsers");
                    }
                };
                context.addRoutes(builder);
                context.start();
            } catch (Exception e) {
                LOGGER.debug("Unable to create camel route.", e);
                return false;
            }
        }
        return true;
    }

    @VisibleForTesting
    String getCronOrDelete() {
        if (!getTempTimestampFilePath().toFile().exists()) {

            // Create temp file and add timestamp
            Instant instant = Instant.now();
            if (!createTempFile(instant)) {
                return null;
            }
            return cronCalculator(instant);

        } else {

            // Read timestamp
            Instant firstInstall = installationDate();
            if (firstInstall == null) {
                return null;
            }

            if (Instant.now().isAfter(firstInstall.plus(Duration.ofDays(3)).minus(Duration.ofMinutes(30)))) { // Timestamp expired
                removeDefaultUsers();
                return null;
            }

            return cronCalculator(firstInstall);
        }
    }

    private boolean createTempFile(Instant instant) {
        try {
            if (getTempTimestampFilePath().toFile().createNewFile()) {
                Files.write(getTempTimestampFilePath(), instant.toString().getBytes(StandardCharsets.UTF_8));
                return true;
            }
        } catch (IOException e) {
            LOGGER.debug("Unable to access the temporary file", e);
        }
        return false;
    }

    public static boolean removeDefaultUsers() {
        try {
            Bundle bundle = FrameworkUtil.getBundle(DefaultUsersDeletionScheduler.class);
            if (bundle != null) {
                BundleContext bundleContext = bundle.getBundleContext();
                Collection<ServiceReference<BackingEngineFactory>> implementers = bundleContext
                        .getServiceReferences(BackingEngineFactory.class, null);
                for (ServiceReference<BackingEngineFactory> impl : implementers) {

                    BackingEngineFactory backingEngineFactory = bundleContext.getService(impl);
                    BackingEngine backingEngine = backingEngineFactory
                            .build(ImmutableMap.of("users", getUsersPropertiesFilePath().toString()));

                    if (!backingEngine.listUsers().isEmpty()) {
                        backingEngine.listUsers().forEach(user -> backingEngine.deleteUser(user.getName()));
                    }
                }
            }

            LOGGER.debug("Default users have been deleted successfully.");

            Files.deleteIfExists(getTempTimestampFilePath());
            return true;
        } catch (Exception e) {
            LOGGER.debug("Unable to remove default users.", e);
            return false;
        }
    }

    private String cronCalculator(Instant firstInstall) {
        Instant threeDayTimestamp = firstInstall.plus(Duration.ofDays(3).minus(Duration.ofMinutes(30)));
        LocalDateTime localDateTime = LocalDateTime.ofInstant(threeDayTimestamp, ZoneId.systemDefault());

        return String.format("%d+%d+%d+%d+%d+?+%d", localDateTime.getSecond(), localDateTime.getMinute(),
                localDateTime.getHour(), localDateTime.getDayOfMonth(), localDateTime.getMonthValue(),
                localDateTime.getYear());
    }

    public Instant installationDate() {
        if (!getTempTimestampFilePath().toFile().exists()) {
            return null;
        }

        try (Stream<String> lines = Files.lines(getTempTimestampFilePath(), StandardCharsets.UTF_8)) {
            return lines.filter(StringUtils::isNotBlank).map(Instant::parse).findFirst().orElse(null);

        } catch (IOException e) {
            LOGGER.debug("Unable to read installation date.", e);
            return null;
        }
    }

    public void deleteScheduledDeletions() {
        try {
            if (context.getRoute(ROUTE_ID) != null && context.getRouteStatus(ROUTE_ID).isStarted()
                    && context.getRouteStatus(ROUTE_ID).isStoppable()) {
                context.stopRoute(ROUTE_ID);
                Files.deleteIfExists(getTempTimestampFilePath());
                LOGGER.debug("The deletion of default users has been stopped successfully.");
            }
        } catch (Exception e) {
            LOGGER.debug("Unable to stop deletion.", e);
        }
    }

    public boolean defaultUsersExist() {
        try (Stream<String> defaultUsers = Files.lines(getUsersPropertiesFilePath(), StandardCharsets.UTF_8)) {
            return defaultUsers.filter(StringUtils::isNotBlank).filter(line -> !line.startsWith("#"))
                    .anyMatch(line -> true);
        } catch (IOException e) {
            LOGGER.debug("Unable to access users.properties file.", e);
            return true;
        }
    }

    public static Path getUsersPropertiesFilePath() {
        return usersPropertiesFilePath;
    }

    public static void setUsersPropertiesFilePath(Path usersPropertiesFilePath) {
        DefaultUsersDeletionScheduler.usersPropertiesFilePath = usersPropertiesFilePath;
    }

    public static Path getTempTimestampFilePath() {
        return tempTimestampFilePath;
    }

    public static void setTempTimestampFilePath(Path tempTimestampFilePath) {
        DefaultUsersDeletionScheduler.tempTimestampFilePath = tempTimestampFilePath;
    }
}