/* (c) 2016 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.backuprestore.tasklet;
import java.io.IOException;
import java.util.logging.Level;
import org.geoserver.backuprestore.Backup;
import org.geoserver.backuprestore.utils.BackupUtils;
import org.geoserver.catalog.ValidationResult;
import org.geoserver.config.GeoServerDataDirectory;
import org.geoserver.config.util.XStreamPersisterFactory;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Paths;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resources;
import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.SecurityManagerListener;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.util.Assert;
/**
* Concrete implementation of the {@link AbstractCatalogBackupRestoreTasklet}.
* <br>
* Actually takes care of dumping/restoring GeoServer Security subsystem.
*
* @author Alessio Fabiani, GeoSolutions
*
*/
public class CatalogSecurityManagerTasklet extends AbstractCatalogBackupRestoreTasklet {
public static final String SECURITY_RESOURCE_NAME = "security";
public CatalogSecurityManagerTasklet(Backup backupFacade,
XStreamPersisterFactory xStreamPersisterFactory) {
super(backupFacade, xStreamPersisterFactory);
}
@Override
protected void initialize(StepExecution stepExecution) {
}
@Override
RepeatStatus doExecute(StepContribution contribution, ChunkContext chunkContext,
JobExecution jobExecution) throws Exception {
final GeoServerDataDirectory dd = backupFacade.getGeoServerDataDirectory();
// GeoServer Security Folder
// dd.getResourceStore().get(SECURITY_RESOURCE_NAME);
final Resource security = dd.getSecurity(Paths.BASE);
if (!isNew()) {
/*
* BACKUP Security Resources
*/
final String outputFolderURL = jobExecution.getJobParameters()
.getString(Backup.PARAM_OUTPUT_FILE_PATH);
final Resource targetBackupFolder = Resources.fromURL(outputFolderURL);
final Resource securityTargetResource = BackupUtils.dir(targetBackupFolder, SECURITY_RESOURCE_NAME);
// Copy the Security files into the destination resource
try {
Resources.copy(security, securityTargetResource);
} catch (IOException e) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
e));
}
// Test that the security folder has been correctly saved
GeoServerSecurityManager testGssm = null;
try {
testGssm = new GeoServerSecurityManager(
new GeoServerDataDirectory(targetBackupFolder.dir()));
testGssm.setApplicationContext(Backup.getContext());
testGssm.reload();
// TODO: Perform validation tests here using "testGssm"
// TODO: Save warnings and validation issues on the JobContext
} catch (Exception e) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
e));
} finally {
if (testGssm != null) {
try {
testGssm.destroy();
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Test GeoServerSecurityManager Destry Error!", e);
}
}
}
} else {
/*
* RESTORE Security Resources
*/
/**
* Create a new GeoServerSecurityManager instance using the INPUT DATA DIR.
*
* Try to load the configuration from there and if everything is ok:
* 1. Replace the security folders
* 2. Destroy and reload the appContext GeoServerSecurityManager
* 3. Issue SecurityManagerListener extensions handlePostChanged(...)
*/
final String inputFolderURL = jobExecution.getJobParameters()
.getString(Backup.PARAM_INPUT_FILE_PATH);
final Resource sourceRestoreFolder = Resources.fromURL(inputFolderURL);
final Resource sourceSecurityResource = BackupUtils.dir(sourceRestoreFolder, SECURITY_RESOURCE_NAME);
// Test that the security folder has been correctly saved
GeoServerSecurityManager testGssm = null;
try {
testGssm = new GeoServerSecurityManager(
new GeoServerDataDirectory(
new GeoServerResourceLoader(sourceRestoreFolder.dir())));
testGssm.setApplicationContext(Backup.getContext());
testGssm.reload();
// TODO: Perform more validation tests here using "testGssm"
// TODO: Save detailed warnings and validation issues on the JobContext
} catch (Exception e) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
e));
} finally {
if (testGssm != null) {
try {
testGssm.destroy();
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Test GeoServerSecurityManager Destry Error!", e);
}
}
}
// Copy the Security files into the destination folder
// First of all do a backup of the original security folder
Resource tmpDir = BackupUtils.tmpDir();
try {
Resources.copy(security, tmpDir);
} catch (IOException e) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
new IOException("It was not possible to backup the original Security folder!", e)));
}
if (Resources.exists(security) && !security.delete()) {
// Try to restore the original one
try {
Resources.copy(tmpDir, security);
} catch (IOException e) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
new IOException("It was not possible to fully restore the original Security folder!", e)));
}
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
new IOException("It was not possible to cleanup the target security folder!")));
}
// Do this *ONLY* when DRY-RUN-MODE == OFF
if (!isDryRun()) {
try {
Resources.copy(sourceSecurityResource, security);
} catch (IOException e) {
// Try to restore the original one
try {
Resources.copy(tmpDir, security);
} catch (IOException e1) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
new IOException("It was not possible to fully restore the original Security folder!", e1)));
}
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
e));
}
// Reload Security Context
GeoServerSecurityManager securityContext = GeoServerExtensions
.bean(GeoServerSecurityManager.class);
securityContext.reload();
for (SecurityManagerListener listener : GeoServerExtensions
.extensions(SecurityManagerListener.class)) {
listener.handlePostChanged(securityContext);
}
} else {
// Try to restore the original one
if (Resources.exists(security) && !security.delete()) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
new IOException("It was not possible to cleanup the target security folder!")));
}
try {
Resources.copy(tmpDir, security);
} catch (IOException e) {
logValidationExceptions((ValidationResult) null,
new UnexpectedJobExecutionException(
"Exception occurred while storing GeoServer security and services settings!",
new IOException("It was not possible to fully restore the original Security folder!", e)));
}
}
}
return RepeatStatus.FINISHED;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(backupFacade, "backupFacade must be set");
Assert.notNull(getxStreamPersisterFactory(), "xstream must be set");
}
}