This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository observe. See http://git.codelutin.com/observe.git commit b2f08df37f34be67f5b9664dac4516048f4078f5 Author: Tony CHEMIT <chemit@codelutin.com> Date: Mon Aug 31 00:30:59 2015 +0200 Gestion de la sécurité de l'application web bien avancée. Mais il faudrait revoir le requestContext car je ne suis pas satisfait de ce que j'ai fait, il vaudrait mieux introduire un RequestSecurityContext et n'avoir q'un seul type de RequestContext. (See #7494) --- .../web/ObserveWebApplicationContext.java | 29 ++- .../application/web/ObserveWebMotionFilter.java | 85 +++++++- .../web/configuration/db/ObserveWebDatabases.java | 2 + .../db/ObserveWebDatabasesHelper.java | 26 ++- .../db/impl/ObserveWebDatabasesBean.java | 5 + .../db/impl/ObserveWebDatabasesImmutable.java | 5 + .../configuration/user/ObserveWebUsersHelper.java | 28 ++- .../web/controller/ObserveWebMotionController.java | 35 +++- .../web/controller/v1/ConfigurationController.java | 82 ++++++++ .../controller/v1/DataSourceServiceController.java | 108 ++++++++++ .../web/controller/v1/DocController.java | 40 ---- .../v1/ObserveServiceControllerSupport.java | 34 ++++ .../v1/ReferentialServiceController.java | 31 +-- .../ObserveWebRequestContextConnected.java} | 36 ++-- .../ObserveWebRequestContextNotConnected.java} | 43 ++-- .../ObserveWebRequestContextSupport.java} | 33 +-- ...equestContextWithNoDataSourceConfiguration.java | 47 +++++ .../BadObserveWebUserPasswordException.java | 27 +++ ...urceConfigurationAlreadyRegistredException.java | 27 +++ .../InvalidAuthenticationTokenException.java | 22 ++ .../ObserveWebSecurityApplicationContext.java | 224 +++++++++++++++++++++ ...ObserveWebSecurityAuthenticationTokenCache.java | 84 ++++++++ .../security/UnknownObserveWebUserException.java | 21 ++ .../UnknownObserveWebUserForDatabaseException.java | 27 +++ observe-application-web/src/main/resources/mapping | 3 +- 25 files changed, 955 insertions(+), 149 deletions(-) diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebApplicationContext.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebApplicationContext.java index a487916..48d38c8 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebApplicationContext.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebApplicationContext.java @@ -12,6 +12,7 @@ import fr.ird.observe.application.web.configuration.user.InvalidObserveWebUserPe import fr.ird.observe.application.web.configuration.user.InvalidObserveWebUsersException; import fr.ird.observe.application.web.configuration.user.ObserveWebUsers; import fr.ird.observe.application.web.configuration.user.ObserveWebUsersHelper; +import fr.ird.observe.application.web.security.ObserveWebSecurityApplicationContext; import fr.ird.observe.services.ObserveService; import fr.ird.observe.services.ObserveServiceApplicationContext; import fr.ird.observe.services.ObserveServiceFactory; @@ -44,6 +45,8 @@ public class ObserveWebApplicationContext implements Closeable { protected ObserveWebUsers users; + protected ObserveWebSecurityApplicationContext securityApplicationContext; + public static ObserveWebApplicationContext getApplicationContext(HttpContext context) { ServletContext servletContext = context.getServletContext(); @@ -71,6 +74,10 @@ public class ObserveWebApplicationContext implements Closeable { ObserveWebUsersHelper usersHelper = new ObserveWebUsersHelper(); users = usersHelper.load(databases, applicationConfiguration.getUsersConfigurationFile()); + // init security application context + securityApplicationContext = new ObserveWebSecurityApplicationContext(); + securityApplicationContext.init(databases, users); + // init service application context serviceApplicationContext = new ObserveServiceApplicationContext(); serviceApplicationContext.setTemporaryDirectoryRoot(applicationConfiguration.getTemporaryDirectory().toPath()); @@ -86,21 +93,13 @@ public class ObserveWebApplicationContext implements Closeable { public void close() { // Supprimer le cache des sessions - //TODO + securityApplicationContext.close(); // Fermer l'usine de services serviceApplicationContext.close(); } - public ObserveWebDatabases getDatabases() { - return databases; - } - - public ObserveWebUsers getUsers() { - return users; - } - public ObserveDtoGsonSupplier getGsonSupplier() { return gsonSupplier; } @@ -109,6 +108,18 @@ public class ObserveWebApplicationContext implements Closeable { return applicationConfiguration; } + public ObserveWebSecurityApplicationContext getSecurityApplicationContext() { + return securityApplicationContext; + } + + public ObserveWebDatabases getDatabases() { + return databases; + } + + public ObserveWebUsers getUsers() { + return users; + } + public <S extends ObserveService> S newService(ObserveDataSourceConfiguration dataSourceConfiguration, Class<S> serviceType) { ObserveServiceFactory mainServiceFactory = serviceApplicationContext.getMainServiceFactory(); return mainServiceFactory.newService(serviceApplicationContext, dataSourceConfiguration, serviceType); diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebMotionFilter.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebMotionFilter.java index 07d7abe..ad8922b 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebMotionFilter.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebMotionFilter.java @@ -1,6 +1,18 @@ package fr.ird.observe.application.web; +import com.google.common.base.Optional; +import fr.ird.observe.application.web.request.ObserveWebRequestContextConnected; +import fr.ird.observe.application.web.request.ObserveWebRequestContextNotConnected; +import fr.ird.observe.application.web.request.ObserveWebRequestContextSupport; +import fr.ird.observe.application.web.request.ObserveWebRequestContextWithNoDataSourceConfiguration; +import fr.ird.observe.application.web.security.BadObserveWebUserPasswordException; +import fr.ird.observe.application.web.security.DataSourceConfigurationAlreadyRegistredException; +import fr.ird.observe.application.web.security.InvalidAuthenticationTokenException; +import fr.ird.observe.application.web.security.ObserveWebSecurityApplicationContext; +import fr.ird.observe.application.web.security.UnknownObserveWebUserException; +import fr.ird.observe.application.web.security.UnknownObserveWebUserForDatabaseException; import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; +import org.apache.commons.lang3.StringUtils; import org.debux.webmotion.server.WebMotionFilter; import org.debux.webmotion.server.call.HttpContext; @@ -11,24 +23,81 @@ import javax.servlet.http.HttpServletRequest; */ public class ObserveWebMotionFilter extends WebMotionFilter { - public void inject(HttpContext context) { + public void inject(HttpContext context) throws InvalidAuthenticationTokenException, UnknownObserveWebUserException, BadObserveWebUserPasswordException, DataSourceConfigurationAlreadyRegistredException, UnknownObserveWebUserForDatabaseException { - ObserveWebApplicationContext applicationContext = - ObserveWebApplicationContext.getApplicationContext(context); + ObserveWebApplicationContext applicationContext = ObserveWebApplicationContext.getApplicationContext(context); HttpServletRequest request = context.getRequest(); - String authenticationToken = request.getHeader("authenticationToken"); + ObserveWebRequestContextSupport requestContext; - //TODO Recuperation de la configuration de la data source de la base à partir du token - ObserveDataSourceConfiguration dataSourceConfiguration = null; + String authenticationToken = getRequestParameterValueOrNull(request, "authenticationToken"); + if (authenticationToken == null) { + authenticationToken = request.getHeader("authenticationToken"); + } - ObserveWebRequestContext requestContext = new ObserveWebRequestContext(applicationContext, dataSourceConfiguration); + if (StringUtils.isNotBlank(authenticationToken)) { - ObserveWebRequestContext.setRequestContext(context, requestContext); + // Recherche de la configuration à la source de donnée + + requestContext = getObserveWebRequestContextConnected(applicationContext, authenticationToken); + + } else { + + // Cas où on l'utilisateur n'est pas connecté + + String userLogin = getRequestParameterValueOrNull(request, "userLogin"); + String userPassword = getRequestParameterValueOrNull(request, "userPassword"); + String userDatabaseName = getRequestParameterValueOrNull(request, "userDatabaseName"); + + if (!(userLogin == null && userPassword == null)) { + + // On recherche une configuration de source de données à partir de l'identité de l'utilisateur + + requestContext = getObserveWebRequestContextNotConnected(applicationContext, userLogin, userPassword, userDatabaseName); + + } else { + + // Ce cas peut arriver pour des requètes qui ne nécessitent pas de sources de données + // À noter que dans ce cas, on ne sera pas autorisé à créer des services de l'API + + requestContext = new ObserveWebRequestContextWithNoDataSourceConfiguration(applicationContext); + + } + + } + + ObserveWebRequestContextSupport.setRequestContext(context, requestContext); doProcess(); } + protected ObserveWebRequestContextNotConnected getObserveWebRequestContextNotConnected(ObserveWebApplicationContext applicationContext, String userLogin, String userPassword, String userDatabaseName) throws UnknownObserveWebUserException, BadObserveWebUserPasswordException, DataSourceConfigurationAlreadyRegistredException, UnknownObserveWebUserForDatabaseException { + + Optional<String> optionalDatabaseName = Optional.fromNullable(userDatabaseName); + + ObserveWebSecurityApplicationContext securityApplicationContext = applicationContext.getSecurityApplicationContext(); + ObserveDataSourceConfiguration dataSourceConfiguration = securityApplicationContext.getDataSourceConfiguration(userLogin, userPassword, optionalDatabaseName); + ObserveWebRequestContextNotConnected requestContext = new ObserveWebRequestContextNotConnected(applicationContext, dataSourceConfiguration, userLogin, optionalDatabaseName); + return requestContext; + } + + protected ObserveWebRequestContextConnected getObserveWebRequestContextConnected(ObserveWebApplicationContext applicationContext, String authenticationToken) throws InvalidAuthenticationTokenException { + + ObserveWebSecurityApplicationContext securityApplicationContext = applicationContext.getSecurityApplicationContext(); + ObserveDataSourceConfiguration dataSourceConfiguration = securityApplicationContext.getDataSourceConfiguration(authenticationToken); + ObserveWebRequestContextConnected requestContext = new ObserveWebRequestContextConnected(applicationContext, dataSourceConfiguration, authenticationToken); + return requestContext; + + } + + protected String getRequestParameterValueOrNull(HttpServletRequest request, String parameterName) { + String parameterValue = request.getParameter(parameterName); + if (StringUtils.isBlank(parameterValue)) { + parameterValue = null; + } + return parameterValue; + } + } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabases.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabases.java index 7008542..df13f7b 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabases.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabases.java @@ -13,6 +13,8 @@ public interface ObserveWebDatabases<D extends ObserveWebDatabase> { Collection<D> getDatabases(); + String getDefaultDatabaseName(); + D getDefaultDatabase(); Optional<D> getDatabaseByName(String databaseName); diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabasesHelper.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabasesHelper.java index cd3e21b..7e2e3cc 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabasesHelper.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/ObserveWebDatabasesHelper.java @@ -1,6 +1,7 @@ package fr.ird.observe.application.web.configuration.db; import com.esotericsoftware.yamlbeans.YamlConfig; +import com.esotericsoftware.yamlbeans.YamlException; import com.esotericsoftware.yamlbeans.YamlReader; import com.esotericsoftware.yamlbeans.YamlWriter; import com.google.common.base.Charsets; @@ -17,6 +18,7 @@ import org.apache.commons.logging.LogFactory; import java.io.BufferedWriter; import java.io.File; import java.io.Reader; +import java.io.Writer; import java.util.LinkedHashSet; import java.util.Set; @@ -137,22 +139,30 @@ public class ObserveWebDatabasesHelper { log.info("Store databases to " + file); } - try (BufferedWriter fileWriter = Files.newWriter(file, Charsets.UTF_8)) { - YamlWriter writer = new YamlWriter(fileWriter, createConfig()); - if (databases instanceof ObserveWebDatabasesImmutable) { + try (BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8)) { - ObserveWebDatabasesImmutable observeWebDatabasesImmutable = (ObserveWebDatabasesImmutable) databases; - databases = observeWebDatabasesImmutable.toBean(); + store(databases, writer); - } - writer.write(databases); - writer.close(); } catch (Exception e) { throw new RuntimeException("Could not write databases to file: " + file, e); } } + public void store(ObserveWebDatabases databases, Writer writer) throws YamlException { + + YamlWriter yamlWriter = new YamlWriter(writer, createConfig()); + if (databases instanceof ObserveWebDatabasesImmutable) { + + ObserveWebDatabasesImmutable observeWebDatabasesImmutable = (ObserveWebDatabasesImmutable) databases; + databases = observeWebDatabasesImmutable.toBean(); + + } + yamlWriter.write(databases); + yamlWriter.close(); + + } + protected YamlConfig createConfig() { YamlConfig yamlConfig = new YamlConfig(); diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesBean.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesBean.java index 646c9b3..ef71705 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesBean.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesBean.java @@ -27,6 +27,11 @@ public class ObserveWebDatabasesBean implements ObserveWebDatabases<ObserveWebDa } @Override + public String getDefaultDatabaseName() { + throw new UnsupportedOperationException("Can not call this method on bean version, use immutable one."); + } + + @Override public ObserveWebDatabaseBean getDefaultDatabase() { throw new UnsupportedOperationException("Can not call this method on bean version, use immutable one."); } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesImmutable.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesImmutable.java index c579b0d..216a930 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesImmutable.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/db/impl/ObserveWebDatabasesImmutable.java @@ -48,6 +48,11 @@ public class ObserveWebDatabasesImmutable implements ObserveWebDatabases<Observe } @Override + public String getDefaultDatabaseName() { + return defaultDatabase.getName(); + } + + @Override public ObserveWebDatabaseImmutable getDefaultDatabase() { return defaultDatabase; } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/user/ObserveWebUsersHelper.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/user/ObserveWebUsersHelper.java index db5cc8f..b268948 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/user/ObserveWebUsersHelper.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/configuration/user/ObserveWebUsersHelper.java @@ -1,6 +1,7 @@ package fr.ird.observe.application.web.configuration.user; import com.esotericsoftware.yamlbeans.YamlConfig; +import com.esotericsoftware.yamlbeans.YamlException; import com.esotericsoftware.yamlbeans.YamlReader; import com.esotericsoftware.yamlbeans.YamlWriter; import com.google.common.base.Charsets; @@ -21,6 +22,7 @@ import org.apache.commons.logging.LogFactory; import java.io.BufferedWriter; import java.io.File; import java.io.Reader; +import java.io.Writer; import java.util.LinkedHashSet; import java.util.Set; @@ -131,22 +133,32 @@ public class ObserveWebUsersHelper { log.info("Store users to " + file); } - try (BufferedWriter fileWriter = Files.newWriter(file, Charsets.UTF_8)) { - YamlWriter writer = new YamlWriter(fileWriter, createConfig()); - if (users instanceof ObserveWebUsersImmutable) { + try (BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8)) { - ObserveWebUsersImmutable observeWebUsersImmutable = (ObserveWebUsersImmutable) users; - users = observeWebUsersImmutable.toBean(); + store(users, writer); - } - writer.write(users); - writer.close(); } catch (Exception e) { throw new RuntimeException("Could not write users to file: " + file, e); } } + public void store(ObserveWebUsers users, Writer writer) throws YamlException { + + + YamlWriter yamlWriter = new YamlWriter(writer, createConfig()); + if (users instanceof ObserveWebUsersImmutable) { + + ObserveWebUsersImmutable observeWebUsersImmutable = (ObserveWebUsersImmutable) users; + users = observeWebUsersImmutable.toBean(); + + } + yamlWriter.write(users); + yamlWriter.close(); + + + } + protected YamlConfig createConfig() { YamlConfig yamlConfig = new YamlConfig(); diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/ObserveWebMotionController.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/ObserveWebMotionController.java index 1844495..df6763e 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/ObserveWebMotionController.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/ObserveWebMotionController.java @@ -1,8 +1,11 @@ package fr.ird.observe.application.web.controller; import fr.ird.observe.application.web.ObserveWebApplicationContext; -import fr.ird.observe.application.web.ObserveWebRequestContext; import fr.ird.observe.application.web.configuration.ObserveWebApplicationConfiguration; +import fr.ird.observe.application.web.request.ObserveWebRequestContextConnected; +import fr.ird.observe.application.web.request.ObserveWebRequestContextNotConnected; +import fr.ird.observe.application.web.request.ObserveWebRequestContextSupport; +import fr.ird.observe.application.web.request.ObserveWebRequestContextWithNoDataSourceConfiguration; import fr.ird.observe.services.ObserveService; import org.debux.webmotion.server.WebMotionController; @@ -20,8 +23,36 @@ public abstract class ObserveWebMotionController extends WebMotionController { } public <S extends ObserveService> S newService(Class<S> serviceType) { - ObserveWebRequestContext requestContext = ObserveWebRequestContext.getRequestContext(getContext()); + ObserveWebRequestContextSupport requestContext = ObserveWebRequestContextSupport.getRequestContext(getContext()); + + if (!requestContext.isCanCreateService()) { + throw new IllegalStateException("The request context " + requestContext + " can not create service"); + } S service = requestContext.newService(serviceType); return service; } + + public ObserveWebRequestContextNotConnected getObserveWebRequestContextNotConnected() { + ObserveWebRequestContextSupport requestContext = ObserveWebRequestContextSupport.getRequestContext(getContext()); + if (!(requestContext instanceof ObserveWebRequestContextNotConnected)) { + throw new IllegalStateException("Bad request context type"); + } + return (ObserveWebRequestContextNotConnected) requestContext; + } + + public ObserveWebRequestContextConnected getObserveWebRequestContextConnected() { + ObserveWebRequestContextSupport requestContext = ObserveWebRequestContextSupport.getRequestContext(getContext()); + if (!(requestContext instanceof ObserveWebRequestContextConnected)) { + throw new IllegalStateException("Bad request context type"); + } + return (ObserveWebRequestContextConnected) requestContext; + } + + public ObserveWebRequestContextWithNoDataSourceConfiguration getObserveWebRequestContextWithNoDataSourceConfiguration() { + ObserveWebRequestContextSupport requestContext = ObserveWebRequestContextSupport.getRequestContext(getContext()); + if (!(requestContext instanceof ObserveWebRequestContextWithNoDataSourceConfiguration)) { + throw new IllegalStateException("Bad request context type"); + } + return (ObserveWebRequestContextWithNoDataSourceConfiguration) requestContext; + } } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ConfigurationController.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ConfigurationController.java new file mode 100644 index 0000000..579e2c5 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ConfigurationController.java @@ -0,0 +1,82 @@ +package fr.ird.observe.application.web.controller.v1; + +import fr.ird.observe.application.web.configuration.db.ObserveWebDatabases; +import fr.ird.observe.application.web.configuration.db.ObserveWebDatabasesHelper; +import fr.ird.observe.application.web.configuration.user.ObserveWebUsers; +import fr.ird.observe.application.web.configuration.user.ObserveWebUsersHelper; +import fr.ird.observe.application.web.controller.ObserveWebMotionController; +import org.apache.commons.io.IOUtils; +import org.debux.webmotion.server.render.Render; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; + +/** + * Created on 8/30/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class ConfigurationController extends ObserveWebMotionController { + + public Render mapping() { + + InputStream mappingUrl = getClass().getResourceAsStream("/mapping"); + + try { + + String content = IOUtils.toString(mappingUrl); + return renderContent(content, "text/plain"); + + } catch (IOException e) { + + throw new RuntimeException(e); + + } + + } + + public Render configuration() { + + String content = getObserveWebApplicationConfiguration().getConfigurationDescription(); + return renderContent(content, "text/plain"); + + } + + public Render databases() throws IOException { + + + String content; + try (StringWriter writer = new StringWriter()) { + + ObserveWebDatabasesHelper observeWebDatabasesHelper = new ObserveWebDatabasesHelper(); + ObserveWebDatabases databases = getObserveWebApplicationContext().getDatabases(); + observeWebDatabasesHelper.store(databases, writer); + + writer.flush(); + content = writer.toString(); + + } + return renderContent(content, "text/plain"); + + } + + public Render users() throws IOException { + + String content; + try (StringWriter writer = new StringWriter()) { + + ObserveWebUsersHelper observeWebUsersHelper = new ObserveWebUsersHelper(); + ObserveWebUsers databases = getObserveWebApplicationContext().getUsers(); + observeWebUsersHelper.store(databases, writer); + + writer.flush(); + content = writer.toString(); + + } + return renderContent(content, "text/plain"); + + } + + +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/DataSourceServiceController.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/DataSourceServiceController.java new file mode 100644 index 0000000..05adeea --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/DataSourceServiceController.java @@ -0,0 +1,108 @@ +package fr.ird.observe.application.web.controller.v1; + +import com.google.common.base.Optional; +import fr.ird.observe.application.web.request.ObserveWebRequestContextConnected; +import fr.ird.observe.application.web.request.ObserveWebRequestContextNotConnected; +import fr.ird.observe.application.web.security.DataSourceConfigurationAlreadyRegistredException; +import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; +import fr.ird.observe.services.dto.DataSourceCreateConfigurationDto; +import fr.ird.observe.services.dto.DataSourceCreateWithNoReferentialImportException; +import fr.ird.observe.services.dto.IncompatibleDataSourceCreateConfigurationException; +import fr.ird.observe.services.service.DataSourceService; +import fr.ird.observe.services.service.DatabaseConnexionNotAuthorizedException; +import fr.ird.observe.services.service.DatabaseNotFoundException; +import fr.ird.observe.services.spi.NoDataAccess; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class DataSourceServiceController extends ObserveServiceControllerSupport<DataSourceService> implements DataSourceService { + + /** Logger. */ + private static final Log log = LogFactory.getLog(DataSourceServiceController.class); + + public DataSourceServiceController() { + super(DataSourceService.class); + } + + @NoDataAccess + public boolean exists() { + return service.exists(); + } + + @NoDataAccess + public boolean canConnect() { + return service.canConnect(); + } + + @NoDataAccess + public void create(DataSourceCreateConfigurationDto dataSourceCreateConfiguration) throws IncompatibleDataSourceCreateConfigurationException, DataSourceCreateWithNoReferentialImportException { + service.create(dataSourceCreateConfiguration); + + ObserveWebRequestContextNotConnected requestContext = getObserveWebRequestContextNotConnected(); + ObserveDataSourceConfiguration dataSourceConfiguration = requestContext.getDataSourceConfiguration(); + + String userLogin = requestContext.getUserLogin(); + Optional<String> optionalDatabaseName = requestContext.getOptionalDatabaseName(); + String authenticationToken; + try { + authenticationToken = getObserveWebApplicationContext().getSecurityApplicationContext().registerDataSourceConfiguration(userLogin, optionalDatabaseName, dataSourceConfiguration); + } catch (DataSourceConfigurationAlreadyRegistredException e) { + throw new RuntimeException("DataSource already registred", e); + } + if (log.isInfoEnabled()) { + log.info("New authenticationToken: " + authenticationToken + " for " + dataSourceConfiguration); + } + + //TODO Voir comment retourner le jeton de sécurité + getContext().getResponse().addHeader("authenticationToken", authenticationToken); + + } + + @NoDataAccess + public void open() throws DatabaseNotFoundException, DatabaseConnexionNotAuthorizedException { + + service.open(); + + ObserveWebRequestContextNotConnected requestContext = getObserveWebRequestContextNotConnected(); + ObserveDataSourceConfiguration dataSourceConfiguration = requestContext.getDataSourceConfiguration(); + + String userLogin = requestContext.getUserLogin(); + Optional<String> optionalDatabaseName = requestContext.getOptionalDatabaseName(); + String authenticationToken; + try { + authenticationToken = getObserveWebApplicationContext().getSecurityApplicationContext().registerDataSourceConfiguration(userLogin, optionalDatabaseName, dataSourceConfiguration); + } catch (DataSourceConfigurationAlreadyRegistredException e) { + throw new RuntimeException("DataSource already registred", e); + } + if (log.isInfoEnabled()) { + log.info("New authenticationToken: " + authenticationToken + " for " + dataSourceConfiguration); + } + + //TODO Voir comment retourner le jeton de sécurité + getContext().getResponse().addHeader("authenticationToken", authenticationToken); + + } + + public void close() { + + service.close(); + + ObserveWebRequestContextConnected requestContext = getObserveWebRequestContextConnected(); + String authenticationToken = requestContext.getAuthenticationToken(); + getObserveWebApplicationContext().getSecurityApplicationContext().invalidateAuthenticationToken(authenticationToken); + if (log.isInfoEnabled()) { + log.info("Invalidate authenticationToken: " + authenticationToken); + } + + } + + public void destroy() { + service.destroy(); + } + +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/DocController.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/DocController.java deleted file mode 100644 index 168d6f2..0000000 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/DocController.java +++ /dev/null @@ -1,40 +0,0 @@ -package fr.ird.observe.application.web.controller.v1; - -import fr.ird.observe.application.web.controller.ObserveWebMotionController; -import org.apache.commons.io.IOUtils; -import org.debux.webmotion.server.render.Render; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Created on 8/30/15. - * - * @author Tony Chemit - chemit@codelutin.com - */ -public class DocController extends ObserveWebMotionController { - - public Render mapping() { - - InputStream mappingUrl = getClass().getResourceAsStream("/mapping"); - - try { - - String content = IOUtils.toString(mappingUrl); - return renderContent(content, "text/plain"); - - } catch (IOException e) { - - throw new RuntimeException(e); - - } - - } - - public Render configuration() { - - String content = getObserveWebApplicationConfiguration().getConfigurationDescription(); - return renderContent(content, "text/plain"); - - } -} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ObserveServiceControllerSupport.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ObserveServiceControllerSupport.java new file mode 100644 index 0000000..68d3fdf --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ObserveServiceControllerSupport.java @@ -0,0 +1,34 @@ +package fr.ird.observe.application.web.controller.v1; + +import fr.ird.observe.application.web.controller.ObserveWebMotionController; +import fr.ird.observe.services.ObserveService; +import fr.ird.observe.services.ObserveServiceContext; +import org.debux.webmotion.server.WebMotionContextable; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public abstract class ObserveServiceControllerSupport<S extends ObserveService> extends ObserveWebMotionController implements ObserveService { + + protected S service; + + protected final Class<S> serviceType; + + protected ObserveServiceControllerSupport(Class<S> serviceType) { + this.serviceType = serviceType; + } + + @Override + public void setContextable(WebMotionContextable contextable) { + super.setContextable(contextable); + service = newService(serviceType); + } + + @Override + public void setServiceContext(ObserveServiceContext serviceContext) { + // Non utilisé ici + } + +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ReferentialServiceController.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ReferentialServiceController.java index 35c8541..fc35ea0 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ReferentialServiceController.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/controller/v1/ReferentialServiceController.java @@ -1,14 +1,11 @@ package fr.ird.observe.application.web.controller.v1; -import fr.ird.observe.application.web.controller.ObserveWebMotionController; -import fr.ird.observe.services.ObserveServiceContext; import fr.ird.observe.services.dto.FormDto; import fr.ird.observe.services.dto.ReferenceSetDto; import fr.ird.observe.services.dto.referential.ReferentialDto; import fr.ird.observe.services.service.DataNotFoundException; import fr.ird.observe.services.service.ReferentialService; import fr.ird.observe.services.spi.Write; -import org.debux.webmotion.server.WebMotionContextable; import java.util.Collection; @@ -17,56 +14,48 @@ import java.util.Collection; * * @author Tony Chemit - chemit@codelutin.com */ -public class ReferentialServiceController extends ObserveWebMotionController implements ReferentialService { +public class ReferentialServiceController extends ObserveServiceControllerSupport<ReferentialService> implements ReferentialService { - protected ReferentialService referentialService; - - @Override - public void setContextable(WebMotionContextable contextable) { - super.setContextable(contextable); - referentialService = newService(ReferentialService.class); + public ReferentialServiceController() { + super(ReferentialService.class); } @Override public <R extends ReferentialDto> ReferenceSetDto<R> getReferentialReferenceSet(Class<R> type) { - return referentialService.getReferentialReferenceSet(type); + return service.getReferentialReferenceSet(type); } @Override public <R extends ReferentialDto> FormDto<R> loadToRead(Class<R> type, String id) throws DataNotFoundException { - return referentialService.loadToRead(type, id); + return service.loadToRead(type, id); } @Override public <R extends ReferentialDto> FormDto<R> loadToEdit(Class<R> type, String id) throws DataNotFoundException { - return referentialService.loadToEdit(type, id); + return service.loadToEdit(type, id); } @Override public <R extends ReferentialDto> FormDto<R> preCreate(Class<R> type) { - return referentialService.preCreate(type); + return service.preCreate(type); } @Override @Write public <R extends ReferentialDto> String save(FormDto<R> form) { - return referentialService.save(form); + return service.save(form); } @Override @Write public <R extends ReferentialDto> void delete(Class<R> type, String id) throws DataNotFoundException { - referentialService.delete(type, id); + service.delete(type, id); } @Override @Write public <R extends ReferentialDto> void delete(Class<R> type, Collection<String> ids) throws DataNotFoundException { - referentialService.delete(type, ids); + service.delete(type, ids); } - @Override - public void setServiceContext(ObserveServiceContext serviceContext) { - // Non utilisé ici - } } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextConnected.java similarity index 55% copy from observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java copy to observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextConnected.java index 9846742..1adb3de 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextConnected.java @@ -1,4 +1,4 @@ -package fr.ird.observe.application.web; +package fr.ird.observe.application.web.request; /* * #%L @@ -21,9 +21,9 @@ package fr.ird.observe.application.web; * #L% */ +import fr.ird.observe.application.web.ObserveWebApplicationContext; import fr.ird.observe.services.ObserveService; import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; -import org.debux.webmotion.server.call.HttpContext; /** * Created on 4/25/14. @@ -31,35 +31,33 @@ import org.debux.webmotion.server.call.HttpContext; * @author Tony Chemit <chemit@codelutin.com> * @since 2.0 */ -public class ObserveWebRequestContext { +public class ObserveWebRequestContextConnected extends ObserveWebRequestContextSupport { - protected static final String REQUEST_OBSERVE_WEB_REQUEST_CONTEXT = ObserveWebRequestContext.class.getName(); + protected final ObserveDataSourceConfiguration dataSourceConfiguration; - public static ObserveWebRequestContext getRequestContext(HttpContext httpContext) { + protected final String authenticationToken; - ObserveWebRequestContext result = (ObserveWebRequestContext) - httpContext.getRequest().getAttribute(REQUEST_OBSERVE_WEB_REQUEST_CONTEXT); - return result; + public ObserveWebRequestContextConnected(ObserveWebApplicationContext webApplicationContext, + ObserveDataSourceConfiguration dataSourceConfiguration, + String authenticationToken) { + super(webApplicationContext, true); + this.dataSourceConfiguration = dataSourceConfiguration; + this.authenticationToken = authenticationToken; } - public static void setRequestContext(HttpContext httpContext, - ObserveWebRequestContext serviceContext) { - httpContext.getRequest().setAttribute(REQUEST_OBSERVE_WEB_REQUEST_CONTEXT, serviceContext); + public String getAuthenticationToken() { + return authenticationToken; } - protected final ObserveWebApplicationContext webApplicationContext; - - protected final ObserveDataSourceConfiguration dataSourceConfiguration; - - public ObserveWebRequestContext(ObserveWebApplicationContext webApplicationContext, - ObserveDataSourceConfiguration dataSourceConfiguration) { - this.webApplicationContext = webApplicationContext; - this.dataSourceConfiguration = dataSourceConfiguration; + public ObserveDataSourceConfiguration getDataSourceConfiguration() { + return dataSourceConfiguration; } public <S extends ObserveService> S newService(Class<S> serviceType) { + S service = webApplicationContext.newService(dataSourceConfiguration, serviceType); return service; + } } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextNotConnected.java similarity index 54% copy from observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java copy to observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextNotConnected.java index 9846742..e34778f 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextNotConnected.java @@ -1,4 +1,4 @@ -package fr.ird.observe.application.web; +package fr.ird.observe.application.web.request; /* * #%L @@ -21,9 +21,10 @@ package fr.ird.observe.application.web; * #L% */ +import com.google.common.base.Optional; +import fr.ird.observe.application.web.ObserveWebApplicationContext; import fr.ird.observe.services.ObserveService; import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; -import org.debux.webmotion.server.call.HttpContext; /** * Created on 4/25/14. @@ -31,35 +32,41 @@ import org.debux.webmotion.server.call.HttpContext; * @author Tony Chemit <chemit@codelutin.com> * @since 2.0 */ -public class ObserveWebRequestContext { +public class ObserveWebRequestContextNotConnected extends ObserveWebRequestContextSupport { - protected static final String REQUEST_OBSERVE_WEB_REQUEST_CONTEXT = ObserveWebRequestContext.class.getName(); + protected final String userLogin; - public static ObserveWebRequestContext getRequestContext(HttpContext httpContext) { + protected final Optional<String> optionalDatabaseName; - ObserveWebRequestContext result = (ObserveWebRequestContext) - httpContext.getRequest().getAttribute(REQUEST_OBSERVE_WEB_REQUEST_CONTEXT); - return result; - } + protected final ObserveDataSourceConfiguration dataSourceConfiguration; - public static void setRequestContext(HttpContext httpContext, - ObserveWebRequestContext serviceContext) { - httpContext.getRequest().setAttribute(REQUEST_OBSERVE_WEB_REQUEST_CONTEXT, serviceContext); + public ObserveWebRequestContextNotConnected(ObserveWebApplicationContext webApplicationContext, + ObserveDataSourceConfiguration dataSourceConfiguration, + String userLogin, + Optional<String> optionalDatabaseName) { + super(webApplicationContext, true); + this.dataSourceConfiguration = dataSourceConfiguration; + this.userLogin = userLogin; + this.optionalDatabaseName = optionalDatabaseName; } - protected final ObserveWebApplicationContext webApplicationContext; + public String getUserLogin() { + return userLogin; + } - protected final ObserveDataSourceConfiguration dataSourceConfiguration; + public Optional<String> getOptionalDatabaseName() { + return optionalDatabaseName; + } - public ObserveWebRequestContext(ObserveWebApplicationContext webApplicationContext, - ObserveDataSourceConfiguration dataSourceConfiguration) { - this.webApplicationContext = webApplicationContext; - this.dataSourceConfiguration = dataSourceConfiguration; + public ObserveDataSourceConfiguration getDataSourceConfiguration() { + return dataSourceConfiguration; } public <S extends ObserveService> S newService(Class<S> serviceType) { + S service = webApplicationContext.newService(dataSourceConfiguration, serviceType); return service; + } } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextSupport.java similarity index 62% rename from observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java rename to observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextSupport.java index 9846742..f402af9 100644 --- a/observe-application-web/src/main/java/fr/ird/observe/application/web/ObserveWebRequestContext.java +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextSupport.java @@ -1,4 +1,4 @@ -package fr.ird.observe.application.web; +package fr.ird.observe.application.web.request; /* * #%L @@ -21,8 +21,8 @@ package fr.ird.observe.application.web; * #L% */ +import fr.ird.observe.application.web.ObserveWebApplicationContext; import fr.ird.observe.services.ObserveService; -import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; import org.debux.webmotion.server.call.HttpContext; /** @@ -31,35 +31,38 @@ import org.debux.webmotion.server.call.HttpContext; * @author Tony Chemit <chemit@codelutin.com> * @since 2.0 */ -public class ObserveWebRequestContext { +public abstract class ObserveWebRequestContextSupport { - protected static final String REQUEST_OBSERVE_WEB_REQUEST_CONTEXT = ObserveWebRequestContext.class.getName(); + protected static final String REQUEST_OBSERVE_WEB_REQUEST_CONTEXT = ObserveWebRequestContextSupport.class.getName(); - public static ObserveWebRequestContext getRequestContext(HttpContext httpContext) { + public static ObserveWebRequestContextSupport getRequestContext(HttpContext httpContext) { - ObserveWebRequestContext result = (ObserveWebRequestContext) + ObserveWebRequestContextSupport result = (ObserveWebRequestContextSupport) httpContext.getRequest().getAttribute(REQUEST_OBSERVE_WEB_REQUEST_CONTEXT); return result; } public static void setRequestContext(HttpContext httpContext, - ObserveWebRequestContext serviceContext) { + ObserveWebRequestContextSupport serviceContext) { httpContext.getRequest().setAttribute(REQUEST_OBSERVE_WEB_REQUEST_CONTEXT, serviceContext); } protected final ObserveWebApplicationContext webApplicationContext; + protected final boolean canCreateService; - protected final ObserveDataSourceConfiguration dataSourceConfiguration; - - public ObserveWebRequestContext(ObserveWebApplicationContext webApplicationContext, - ObserveDataSourceConfiguration dataSourceConfiguration) { + public ObserveWebRequestContextSupport(ObserveWebApplicationContext webApplicationContext, boolean canCreateService) { this.webApplicationContext = webApplicationContext; - this.dataSourceConfiguration = dataSourceConfiguration; + this.canCreateService = canCreateService; + } + + public ObserveWebApplicationContext getWebApplicationContext() { + return webApplicationContext; } - public <S extends ObserveService> S newService(Class<S> serviceType) { - S service = webApplicationContext.newService(dataSourceConfiguration, serviceType); - return service; + public boolean isCanCreateService() { + return canCreateService; } + public abstract <S extends ObserveService> S newService(Class<S> serviceType); + } diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextWithNoDataSourceConfiguration.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextWithNoDataSourceConfiguration.java new file mode 100644 index 0000000..6abfac1 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/request/ObserveWebRequestContextWithNoDataSourceConfiguration.java @@ -0,0 +1,47 @@ +package fr.ird.observe.application.web.request; + +/* + * #%L + * Pollen :: Rest Api + * %% + * Copyright (C) 2009 - 2014 CodeLutin + * %% + * 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 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/>. + * #L% + */ + +import fr.ird.observe.application.web.ObserveWebApplicationContext; +import fr.ird.observe.services.ObserveService; +import org.apache.commons.lang3.NotImplementedException; + +/** + * Created on 4/25/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 2.0 + */ +public class ObserveWebRequestContextWithNoDataSourceConfiguration extends ObserveWebRequestContextSupport { + + public ObserveWebRequestContextWithNoDataSourceConfiguration(ObserveWebApplicationContext webApplicationContext) { + super(webApplicationContext, false); + + } + + public <S extends ObserveService> S newService(Class<S> serviceType) { + + throw new NotImplementedException("Not authorize to create observe services from this requestContext."); + + } + +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/BadObserveWebUserPasswordException.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/BadObserveWebUserPasswordException.java new file mode 100644 index 0000000..9518e5c --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/BadObserveWebUserPasswordException.java @@ -0,0 +1,27 @@ +package fr.ird.observe.application.web.security; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class BadObserveWebUserPasswordException extends Exception{ + + private static final long serialVersionUID = 1L; + + protected final String userLogin; + protected final String userPassword; + + public BadObserveWebUserPasswordException(String userLogin, String userPassword) { + this.userLogin= userLogin; + this.userPassword = userPassword; + } + + public String getUserLogin() { + return userLogin; + } + + public String getUserPassword() { + return userPassword; + } +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/DataSourceConfigurationAlreadyRegistredException.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/DataSourceConfigurationAlreadyRegistredException.java new file mode 100644 index 0000000..1ced100 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/DataSourceConfigurationAlreadyRegistredException.java @@ -0,0 +1,27 @@ +package fr.ird.observe.application.web.security; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class DataSourceConfigurationAlreadyRegistredException extends Exception { + + private static final long serialVersionUID = 1L; + + protected final String databaseName; + protected final String role; + + public DataSourceConfigurationAlreadyRegistredException(String databaseName, String role) { + this.databaseName = databaseName; + this.role = role; + } + + public String getDatabaseName() { + return databaseName; + } + + public String getRole() { + return role; + } +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/InvalidAuthenticationTokenException.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/InvalidAuthenticationTokenException.java new file mode 100644 index 0000000..1ab9212 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/InvalidAuthenticationTokenException.java @@ -0,0 +1,22 @@ +package fr.ird.observe.application.web.security; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class InvalidAuthenticationTokenException extends Exception { + + private static final long serialVersionUID = 1L; + + protected final String authenticationToken; + + public InvalidAuthenticationTokenException(String authenticationToken) { + this.authenticationToken = authenticationToken; + } + + public String getAuthenticationToken() { + return authenticationToken; + } + +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/ObserveWebSecurityApplicationContext.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/ObserveWebSecurityApplicationContext.java new file mode 100644 index 0000000..b5b5942 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/ObserveWebSecurityApplicationContext.java @@ -0,0 +1,224 @@ +package fr.ird.observe.application.web.security; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import fr.ird.observe.application.web.configuration.db.ObserveWebDatabase; +import fr.ird.observe.application.web.configuration.db.ObserveWebDatabaseRole; +import fr.ird.observe.application.web.configuration.db.ObserveWebDatabases; +import fr.ird.observe.application.web.configuration.user.ObserveWebUser; +import fr.ird.observe.application.web.configuration.user.ObserveWebUserPermission; +import fr.ird.observe.application.web.configuration.user.ObserveWebUsers; +import fr.ird.observe.services.ObserveDataSourceConfigurationMainFactory; +import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.Closeable; +import java.util.Objects; + +/** + * Pour conserver les données applicatives liée à la sécurité (principale le cache des utilisateurs connectés). + * + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class ObserveWebSecurityApplicationContext implements Closeable { + + /** Logger. */ + private static final Log log = LogFactory.getLog(ObserveWebSecurityApplicationContext.class); + + /** + * Le cache des jetons de sécurité générés liés aux configurations de sources de données. + */ + protected final ObserveWebSecurityAuthenticationTokenCache authenticateCache; + + /** + * Le cache des configurations disponibles pour les couple (utilisateur#base) connus du système. + * + * @see #getUserKey(String, String) + */ + protected ImmutableMap<String, ObserveDataSourceConfiguration> dataSourceConfigurationCache; + + /** + * Le nom de la base par défaut à utiliser si elle n'est pas spécifiée. + * + * @see ObserveWebDatabases#getDefaultDatabase() + */ + protected String defaultDatabaseName; + + protected ObserveWebDatabases<?> databases; + + protected ObserveWebUsers<?> users; + + public ObserveWebSecurityApplicationContext() { + this.authenticateCache = new ObserveWebSecurityAuthenticationTokenCache(); + } + + public synchronized void init(ObserveWebDatabases<?> databases, ObserveWebUsers<?> users) { + this.databases = databases; + this.users = users; + + authenticateCache.removeAllAuthenticationTokens(); + ObserveWebDatabase defaultDatabase = databases.getDefaultDatabase(); + Preconditions.checkNotNull(defaultDatabase); + defaultDatabaseName = defaultDatabase.getName(); + + ImmutableMap.Builder<String, ObserveDataSourceConfiguration> dataSourceConfigurationsCacheBuilder = new ImmutableMap.Builder<>(); + + ObserveDataSourceConfigurationMainFactory configurationFactory = new ObserveDataSourceConfigurationMainFactory(); + for (ObserveWebUser<?> observeWebUser : users.getUsers()) { + + for (ObserveWebUserPermission observeWebUserPermission : observeWebUser.getPermissions()) { + + String databaseName = observeWebUserPermission.getDatabase(); + Optional<? extends ObserveWebDatabase> optionalDatabase = databases.getDatabaseByName(databaseName); + Preconditions.checkArgument(optionalDatabase.isPresent()); + + ObserveWebDatabase<?> database = optionalDatabase.get(); + + String role = observeWebUserPermission.getRole(); + Optional<? extends ObserveWebDatabaseRole> optionalDatabaseRole = database.getDatabaseRoleByLogin(role); + Preconditions.checkArgument(optionalDatabaseRole.isPresent()); + ObserveWebDatabaseRole databaseRole = optionalDatabaseRole.get(); + + String jdbcUrl = database.getUrl(); + String login = databaseRole.getLogin(); + String password = databaseRole.getPassword(); + String userKey = getUserKey(observeWebUser.getLogin(), databaseName); + + // Create DataSourceConfiguration + ObserveDataSourceConfiguration configuration = configurationFactory.createObserveDataSourceConfigurationTopiaPG( + userKey, + jdbcUrl, + login, + password.toCharArray(), + true + ); + + + if (log.isInfoEnabled()) { + log.info(String.format("Creates data source configuration for userKey %s : %s", userKey, configuration)); + } + dataSourceConfigurationsCacheBuilder.put(userKey, configuration); + + } + + } + + dataSourceConfigurationCache = dataSourceConfigurationsCacheBuilder.build(); + + } + + /** + * Récupére la configuration de la data source associé à l'utilisateur et à la base passé en paramètre. + * + * @param userLogin le login de l'utilisateur + * @param optionalDatabaseName le nom de la base à utiliser + * @return + * @throws UnknownObserveWebUserForDatabaseException + * @throws DataSourceConfigurationAlreadyRegistredException + */ + public ObserveDataSourceConfiguration getDataSourceConfiguration(String userLogin, Optional<String> optionalDatabaseName) throws UnknownObserveWebUserForDatabaseException, DataSourceConfigurationAlreadyRegistredException { + + // Get database name + String databaseName; + if (optionalDatabaseName.isPresent()) { + databaseName = optionalDatabaseName.get(); + } else { + databaseName = defaultDatabaseName; + } + + // Get data source configuration key cache + String userKey = getUserKey(userLogin, databaseName); + if (log.isInfoEnabled()) { + log.info("Try to find data source configuration for: " + userKey); + } + + // Get data source configuration + ObserveDataSourceConfiguration dataSourceConfiguration = dataSourceConfigurationCache.get(userKey); + if (dataSourceConfiguration == null) { + + // unknown userLogin - database + throw new UnknownObserveWebUserForDatabaseException(userLogin, databaseName); + } + + if (log.isInfoEnabled()) { + log.info("Will use database configuration: " + dataSourceConfiguration); + } + + return dataSourceConfiguration; + + } + + public String registerDataSourceConfiguration(String userLogin, Optional<String> optionalDatabaseName, ObserveDataSourceConfiguration dataSourceConfiguration) throws DataSourceConfigurationAlreadyRegistredException { + + // Check if the data source configuration is not already registred in cache + boolean alreadyInCache = authenticateCache.isDataSourceConfigurationInCache(dataSourceConfiguration); + if (alreadyInCache) { + + // Get database name + String databaseName; + if (optionalDatabaseName.isPresent()) { + databaseName = optionalDatabaseName.get(); + } else { + databaseName = defaultDatabaseName; + } + + // can't register twice a user for a database + throw new DataSourceConfigurationAlreadyRegistredException(userLogin, databaseName); + } + + // Register data source configuration in cache + String authenticationToken = authenticateCache.registerDataSourceConfiguration(dataSourceConfiguration); + + return authenticationToken; + + } + + public ObserveDataSourceConfiguration getDataSourceConfiguration(String userLogin, String userPassword, Optional<String> optionalDatabaseName) throws UnknownObserveWebUserException, BadObserveWebUserPasswordException, DataSourceConfigurationAlreadyRegistredException, UnknownObserveWebUserForDatabaseException { + + // Get user + Optional<? extends ObserveWebUser> optionalUser = users.getUserByLogin(userLogin); + if (!optionalUser.isPresent()) { + throw new UnknownObserveWebUserException(userLogin); + } + ObserveWebUser user = optionalUser.get(); + if (!Objects.equals(user.getPassword(), userPassword)) { + throw new BadObserveWebUserPasswordException(userLogin, userPassword); + } + ObserveDataSourceConfiguration dataSourceConfiguration = getDataSourceConfiguration(userLogin, optionalDatabaseName); + return dataSourceConfiguration; + + } + + /** + * Pour récupérer la configuration de la data source à partir d'un jeton d'authentification. + * + * @param authenticationToken le jeton de sécurité + * @return la configuration de la data source associée au jeton + * @throws InvalidAuthenticationTokenException si le jeton n'est pas connu + */ + public ObserveDataSourceConfiguration getDataSourceConfiguration(String authenticationToken) throws InvalidAuthenticationTokenException { + ObserveDataSourceConfiguration dataSourceConfiguration = authenticateCache.getDataSourceConfigurationIfPresent(authenticationToken); + if (dataSourceConfiguration == null) { + throw new InvalidAuthenticationTokenException(authenticationToken); + } + return dataSourceConfiguration; + + } + + public void invalidateAuthenticationToken(String authenticationToken) { + authenticateCache.removeAuthenticationToken(authenticationToken); + } + + @Override + public void close() { + authenticateCache.close(); + } + + protected String getUserKey(String userLogin, String databaseName) { + return userLogin + "--" + databaseName; + } +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/ObserveWebSecurityAuthenticationTokenCache.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/ObserveWebSecurityAuthenticationTokenCache.java new file mode 100644 index 0000000..ecd3de4 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/ObserveWebSecurityAuthenticationTokenCache.java @@ -0,0 +1,84 @@ +package fr.ird.observe.application.web.security; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; +import fr.ird.observe.services.configuration.ObserveDataSourceConfiguration; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * Le cache des jetons d'authentification. + * + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class ObserveWebSecurityAuthenticationTokenCache { + + /** Logger. */ + private static final Log log = LogFactory.getLog(ObserveWebSecurityAuthenticationTokenCache.class); + + /** + * Le cache des jetons de sécurité liés aux configurations de sources de données. + */ + protected final Cache<String, ObserveDataSourceConfiguration> authenticationTokenCache; + + public ObserveWebSecurityAuthenticationTokenCache() { + this.authenticationTokenCache = CacheBuilder.newBuilder() + .maximumSize(10000) + .expireAfterWrite(20, TimeUnit.MINUTES) + .expireAfterAccess(20, TimeUnit.MINUTES) + .removalListener(new RemovalListener<String, ObserveDataSourceConfiguration>() { + + @Override + public void onRemoval(RemovalNotification<String, ObserveDataSourceConfiguration> notification) { + if (log.isInfoEnabled()) { + log.info(String.format("Remove authentication token: %s - %s", notification.getKey(), notification.getValue())); + } + } + }) + .build(); + } + + public ObserveDataSourceConfiguration getDataSourceConfigurationIfPresent(String authenticationToken) { + ObserveDataSourceConfiguration dataSourceConfiguration = authenticationTokenCache.getIfPresent(authenticationToken); + return dataSourceConfiguration; + } + + public boolean isDataSourceConfigurationInCache(ObserveDataSourceConfiguration dataSourceConfiguration) { + boolean inCache = authenticationTokenCache.asMap().containsValue(dataSourceConfiguration); + return inCache; + } + + public String registerDataSourceConfiguration(ObserveDataSourceConfiguration dataSourceConfiguration) { + String authenticationToken = UUID.randomUUID().toString(); + if (log.isInfoEnabled()) { + log.info(String.format("Add authenticationToken: %s for data source configuration: %s", authenticationToken, dataSourceConfiguration)); + } + authenticationTokenCache.put(authenticationToken, dataSourceConfiguration); + return authenticationToken; + } + + public void removeAuthenticationToken(String authenticationToken) { + if (log.isInfoEnabled()) { + log.info(String.format("Remove authenticationToken: %s ", authenticationToken)); + } + authenticationTokenCache.invalidate(authenticationToken); + } + + public void removeAllAuthenticationTokens() { + if (log.isInfoEnabled()) { + log.info("Remove all authenticationTokens"); + } + authenticationTokenCache.invalidateAll(); + } + + public void close() { + removeAllAuthenticationTokens(); + } +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/UnknownObserveWebUserException.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/UnknownObserveWebUserException.java new file mode 100644 index 0000000..4568096 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/UnknownObserveWebUserException.java @@ -0,0 +1,21 @@ +package fr.ird.observe.application.web.security; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class UnknownObserveWebUserException extends Exception { + + private static final long serialVersionUID = 1L; + + protected final String userLogin; + + public UnknownObserveWebUserException(String userLogin) { + this.userLogin= userLogin; + } + + public String getUserLogin() { + return userLogin; + } +} diff --git a/observe-application-web/src/main/java/fr/ird/observe/application/web/security/UnknownObserveWebUserForDatabaseException.java b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/UnknownObserveWebUserForDatabaseException.java new file mode 100644 index 0000000..6ff40f2 --- /dev/null +++ b/observe-application-web/src/main/java/fr/ird/observe/application/web/security/UnknownObserveWebUserForDatabaseException.java @@ -0,0 +1,27 @@ +package fr.ird.observe.application.web.security; + +/** + * Created on 30/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class UnknownObserveWebUserForDatabaseException extends Exception { + + private static final long serialVersionUID = 1L; + + protected final String databaseName; + protected final String role; + + public UnknownObserveWebUserForDatabaseException(String databaseName, String role) { + this.databaseName = databaseName; + this.role = role; + } + + public String getDatabaseName() { + return databaseName; + } + + public String getRole() { + return role; + } +} diff --git a/observe-application-web/src/main/resources/mapping b/observe-application-web/src/main/resources/mapping index 860c553..df7804d 100644 --- a/observe-application-web/src/main/resources/mapping +++ b/observe-application-web/src/main/resources/mapping @@ -40,6 +40,7 @@ default.render=fr.ird.observe.application.web.ObserveWebMotionRender [actions] -GET /api/v1/doc/{method} DocController.{method} +GET /api/v1/configuration/{method} ConfigurationController.{method} GET,POST /api/v1/referential/{method} ReferentialServiceController.{method} +GET,POST /api/v1/dataSource/{method} DataSourceServiceController.{method} -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@list.forge.codelutin.com>.