package at.gv.egovernment.moa.id.auth.modules.auth.dummy.service; import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException; import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EAAFException; import at.gv.egiz.eaaf.core.impl.utils.FileUtils; import at.gv.egiz.eaaf.core.impl.utils.Random; import at.gv.egovernment.moa.id.auth.modules.auth.dummy.ConfigurationProperties; import at.gv.egovernment.moa.logging.Logger; /** * Service that holdes and selects dummy-identities for dummy-authentication. * * @author tlenz * */ public class DummyIdentityService { @Autowired IConfiguration config; private List> availableIdentities = new ArrayList<>(); private static ObjectMapper jsonMapper = new ObjectMapper(); static { // initialize JSON Mapper jsonMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); jsonMapper.configure(DeserializationFeature.FAIL_ON_TRAILING_TOKENS, true); jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); jsonMapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); jsonMapper.setVisibility(PropertyAccessor.GETTER, Visibility.PUBLIC_ONLY); jsonMapper.setVisibility(PropertyAccessor.IS_GETTER, Visibility.PUBLIC_ONLY); } /** * Get an identity randomly from available identities. * * @return Map of identity attributes * @throws EAAFAuthenticationException In case of an empty identity store */ public Map getIdentityRandomly() throws EAAFAuthenticationException { if (availableIdentities.isEmpty()) { throw new EAAFAuthenticationException("builder.08", new Object[] {"No Dummy-Identity available"}); } int num = (int) (Math.random() * 1000000) % availableIdentities.size(); Logger.debug("Select element: " + num + " from dummy-identity store"); return availableIdentities.get(num); } /** * Get number of available identity sets. * * @return available dummy identities */ public int getNumberOfLoadedIdentitySets( ) { return availableIdentities.size(); } @PostConstruct private void initialize() throws EAAFException { try { Logger.debug("Initializing Dummy-Identity authentication service ... "); //get all files from datastore Set identityConfigFiles = getAllFilesFromIdentityStore(); Logger.debug("Find #" + identityConfigFiles.size() + " files in identity-store. Starting identity extraction ... "); //extract identity informations identityConfigFiles.stream() .filter(el -> FilenameUtils.isExtension(el.getFileName().toString(), ConfigurationProperties.ALLOWED_FILE_TYPE)) .forEach(el -> loadJson(el)); Logger.info("Dummy-Identity authentication service contains #" + availableIdentities.size() + " data-sets"); } catch (EAAFException e) { handleError(e); } catch (IOException e) { handleError(new EAAFException("config.05", new Object[] {ConfigurationProperties.PROP_MODULE_IDENTITY_STORE_PATH}, e)); } } private void loadJson(Path file) { try { Logger.debug("Reading dummy-identity from file: " + file.getFileName() + " ... "); Map dummyEid = jsonMapper.readValue(file.toFile(), Map.class); // check minimum required attributes ConfigurationProperties.MINIMUM_REQ_ATTRIBUTES.stream().forEach( el -> { if (!dummyEid.containsKey(el)) { throw new RuntimeException("dummy-identity from file: " + file.getFileName() + " missing attribute: " + el); } }); Logger.debug("Add dummy-identity from file: " + file.getFileName()); availableIdentities.add(dummyEid); } catch (Exception e) { Logger.warn("Can NOT read dummy-identity from file: " + file.getFileName() + " Identity will be skipped", e); } } private Set getAllFilesFromIdentityStore() throws IOException, EAAFConfigurationException { String identityStorePath = config.getBasicConfiguration(ConfigurationProperties.PROP_MODULE_IDENTITY_STORE_PATH); if (StringUtils.isEmpty(identityStorePath)) { throw new EAAFConfigurationException("config.08", new Object[] {ConfigurationProperties.PROP_MODULE_IDENTITY_STORE_PATH}); } String absIdentityStorePath = FileUtils.makeAbsoluteURL(identityStorePath, config.getConfigurationRootDirectory()); if (absIdentityStorePath.startsWith("file:")) { absIdentityStorePath = absIdentityStorePath.substring("file:".length()); } return Files.walk(Paths.get(absIdentityStorePath), FileVisitOption.FOLLOW_LINKS) .filter(Files::isRegularFile) .filter(Files::isReadable) .collect(Collectors.toSet()); } private void handleError(EAAFException e) throws EAAFException { if (config.getBasicConfigurationBoolean(ConfigurationProperties.PROP_MODULE_ENABLED, false)) { throw e; } else { Logger.info("Dummy-Identity authentication is disabled. Ignore exception: " + e.getMessage()); } } }