Tony CHEMIT pushed to branch develop at ultreiaio / ird-observe
Commits:
-
c992ad78
by Tony Chemit at 2022-02-21T09:38:08+01:00
-
981f43b2
by Tony Chemit at 2022-02-21T09:55:39+01:00
-
58a8c0e3
by Tony Chemit at 2022-02-21T12:15:25+01:00
-
9f60f71c
by Tony Chemit at 2022-02-21T14:25:18+01:00
20 changed files:
- core/services/local/src/main/java/fr/ird/observe/services/local/ObserveServiceContextLocal.java
- core/services/local/src/main/java/fr/ird/observe/services/local/service/ObserveServiceLocal.java
- core/services/local/src/test/java/fr/ird/observe/services/local/service/api/DataEntityServiceLocalWriteTest.java
- core/services/test/src/main/java/fr/ird/observe/services/service/api/DataEntityServiceFixtures.java
- pom.xml
- server/configuration-tools/README.md
- server/configuration/src/main/java/fr/ird/observe/server/configuration/ServerConfig.java
- server/configuration/src/main/java/fr/ird/observe/server/configuration/ServerResources.java
- server/configuration/src/test/resources/log.xml → server/configuration/src/test/resources/META-INF/configuration/log.xml
- server/configuration/src/main/resources/defaultSecurity.yml → server/configuration/src/test/resources/META-INF/configuration/security.yml
- server/core/src/main/java/fr/ird/observe/server/controller/AdminController.java
- server/core/src/main/java/fr/ird/observe/server/security/ObserveWebSecurityApplicationContext.java
- server/core/src/main/java/fr/ird/observe/server/security/ObserveWebSecurityConfigCache.java
- server/core/src/main/java/fr/ird/observe/server/security/ObserveWebSecurityConfigCacheKey.java → server/core/src/main/java/fr/ird/observe/server/security/ObserveWebSecurityConfigCacheValue.java
- server/core/src/main/java/fr/ird/observe/server/security/ObserveWebSecuritySessionCache.java
- server/core/src/main/java/fr/ird/observe/server/security/ObserveWebUserSession.java
- server/runner/README.md
- server/runner/src/main/assembly/server.xml
- server/runner/src/main/i18n/translations/server-runner_fr_FR.properties
- server/runner/src/main/resources/log.xml → server/runner/src/main/resources/META-INF/configuration/log.xml
Changes:
| ... | ... | @@ -53,6 +53,11 @@ public final class ObserveServiceContextLocal extends ObserveServicesProviderImp |
| 53 | 53 | private ObserveTopiaApplicationContext topiaApplicationContext;
|
| 54 | 54 | private DecoratorService decoratorService;
|
| 55 | 55 | |
| 56 | + /**
|
|
| 57 | + * If any error was found, will stop any commit then closing transaction.
|
|
| 58 | + */
|
|
| 59 | + private Throwable error;
|
|
| 60 | + |
|
| 56 | 61 | ObserveServiceContextLocal(ObserveServiceInitializer serviceInitializer, ObserveServiceFactory serviceFactory) {
|
| 57 | 62 | super(serviceFactory, () -> serviceInitializer);
|
| 58 | 63 | }
|
| ... | ... | @@ -143,6 +148,17 @@ public final class ObserveServiceContextLocal extends ObserveServicesProviderImp |
| 143 | 148 | return persistenceContext;
|
| 144 | 149 | }
|
| 145 | 150 | |
| 151 | + public Throwable getError() {
|
|
| 152 | + return error;
|
|
| 153 | + }
|
|
| 154 | + |
|
| 155 | + public void setError(Throwable error, String methodName) {
|
|
| 156 | + this.error = Objects.requireNonNull(error);
|
|
| 157 | + if (log.isInfoEnabled()) {
|
|
| 158 | + log.error(String.format("Could not invoke for %s", methodName), error);
|
|
| 159 | + }
|
|
| 160 | + }
|
|
| 161 | + |
|
| 146 | 162 | public void checkCredentials(String methodName, Permission methodeCredentials) {
|
| 147 | 163 | if (methodeCredentials != null && serviceInitializer().withConnection()) {
|
| 148 | 164 | ObserveDataSourceConnection dataSourceConnection = serviceInitializer().getConnection();
|
| ... | ... | @@ -164,7 +180,11 @@ public final class ObserveServiceContextLocal extends ObserveServicesProviderImp |
| 164 | 180 | }
|
| 165 | 181 | |
| 166 | 182 | private void commit(ObserveTopiaPersistenceContext persistenceContext) {
|
| 167 | - log.debug(String.format("Commit persistenceContext for %s", methodName));
|
|
| 168 | - persistenceContext.commit();
|
|
| 183 | + if (error == null) {
|
|
| 184 | + log.debug(String.format("Commit persistenceContext for %s", methodName));
|
|
| 185 | + persistenceContext.commit();
|
|
| 186 | + } else {
|
|
| 187 | + log.warn(String.format("Skip commit persistenceContext for %s, due to error on call...", methodName));
|
|
| 188 | + }
|
|
| 169 | 189 | }
|
| 170 | 190 | } |
| ... | ... | @@ -334,8 +334,6 @@ public abstract class ObserveServiceLocal implements ObserveService, ServiceCont |
| 334 | 334 | |
| 335 | 335 | @Override
|
| 336 | 336 | public final ServiceValidationContext createServiceValidationContext(ValidationRequestConfigurationSupport configuration, ValidationRequest request) {
|
| 337 | -// ObserveServicesProviderImpl servicesProvider = new ObserveServicesProviderImpl(serviceContext.serviceFactory(), serviceContext::serviceInitializer);
|
|
| 338 | -// ServiceValidationContext validationContext = new ServiceValidationContext((ValidationRequestConfiguration) configuration, getDecoratorService(), new ProjectSelectModel(), servicesProvider);
|
|
| 339 | 337 | ServiceValidationContext validationContext = new ServiceValidationContext((ValidationRequestConfiguration) configuration, getDecoratorService(), new Project(), serviceContext);
|
| 340 | 338 | validationContext.init();
|
| 341 | 339 | return validationContext;
|
| ... | ... | @@ -353,12 +351,28 @@ public abstract class ObserveServiceLocal implements ObserveService, ServiceCont |
| 353 | 351 | return serviceContext.initWriteTransaction(methodName, methodeCredentials);
|
| 354 | 352 | }
|
| 355 | 353 | |
| 356 | - protected final void closeTransaction(boolean doClose) {
|
|
| 354 | + protected final void recordError(Exception e, String methodName) {
|
|
| 355 | + serviceContext.setError(e, methodName);
|
|
| 356 | + }
|
|
| 357 | + |
|
| 358 | + protected final void closeTransaction(boolean doClose, long t0, String methodName) {
|
|
| 357 | 359 | if (doClose) {
|
| 358 | - serviceContext.closeTransaction();
|
|
| 360 | + try {
|
|
| 361 | + serviceContext.closeTransaction();
|
|
| 362 | + } finally {
|
|
| 363 | + log(t0, "close transaction", methodName);
|
|
| 364 | + }
|
|
| 359 | 365 | }
|
| 360 | 366 | }
|
| 361 | 367 | |
| 368 | + protected final void logInvokeMethod(long t0, String methodName) {
|
|
| 369 | + log(t0, "invokeMethod", methodName);
|
|
| 370 | + }
|
|
| 371 | + |
|
| 372 | + protected final void log(long t0, String prefix, String methodName) {
|
|
| 373 | + TIME_LOG.log(t0, String.format("%s %s.%s", prefix, getClass().getName(), methodName));
|
|
| 374 | + }
|
|
| 375 | + |
|
| 362 | 376 | protected final ObserveServiceContextLocal serviceContext() {
|
| 363 | 377 | return serviceContext;
|
| 364 | 378 | }
|
| ... | ... | @@ -22,11 +22,11 @@ package fr.ird.observe.services.local.service.api; |
| 22 | 22 | * #L%
|
| 23 | 23 | */
|
| 24 | 24 | |
| 25 | +import fr.ird.observe.dto.ToolkitId;
|
|
| 25 | 26 | import fr.ird.observe.dto.data.DataDto;
|
| 26 | 27 | import fr.ird.observe.dto.db.DataSourceValidationMode;
|
| 27 | 28 | import fr.ird.observe.navigation.tree.io.ToolkitTreeNodeStates;
|
| 28 | 29 | import fr.ird.observe.services.service.api.InvalidDataException;
|
| 29 | -import fr.ird.observe.services.service.data.ps.common.TripService;
|
|
| 30 | 30 | import fr.ird.observe.test.DatabaseName;
|
| 31 | 31 | import fr.ird.observe.test.spi.CopyDatabaseConfiguration;
|
| 32 | 32 | import fr.ird.observe.test.spi.DatabaseNameConfiguration;
|
| ... | ... | @@ -35,6 +35,7 @@ import org.junit.Test; |
| 35 | 35 | |
| 36 | 36 | import java.util.List;
|
| 37 | 37 | import java.util.Map;
|
| 38 | +import java.util.Objects;
|
|
| 38 | 39 | |
| 39 | 40 | public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceLocalWriteTest {
|
| 40 | 41 | @Override
|
| ... | ... | @@ -69,13 +70,13 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 69 | 70 | public void createPsTrip() throws InvalidDataException {
|
| 70 | 71 | TOPIA_TEST_CLASS_RESOURCE.getServiceInitializerConfig().setValidationMode(DataSourceValidationMode.NONE);
|
| 71 | 72 | {
|
| 72 | - List<?> data = assertTrip(TripService.class,
|
|
| 73 | - fr.ird.observe.dto.data.ps.common.TripDto.class, "gearUseFeatures", 1);
|
|
| 73 | + List<?> data = assertCreateTrip(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 74 | + fr.ird.observe.dto.data.ps.common.TripDto.class, "gearUseFeatures", 1);
|
|
| 74 | 75 | Assert.assertNotNull(data);
|
| 75 | 76 | }
|
| 76 | 77 | {
|
| 77 | - List<?> data = assertTrip(TripService.class,
|
|
| 78 | - fr.ird.observe.dto.data.ps.common.TripDto.class, "routeObs", 2);
|
|
| 78 | + List<?> data = assertCreateTrip(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 79 | + fr.ird.observe.dto.data.ps.common.TripDto.class, "routeObs", 2);
|
|
| 79 | 80 | Assert.assertNotNull(data);
|
| 80 | 81 | }
|
| 81 | 82 | }
|
| ... | ... | @@ -88,13 +89,13 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 88 | 89 | TOPIA_TEST_CLASS_RESOURCE.getServiceInitializerConfig().setValidationMode(DataSourceValidationMode.NONE);
|
| 89 | 90 | try {
|
| 90 | 91 | {
|
| 91 | - List<?> data = assertTrip(TripService.class,
|
|
| 92 | - fr.ird.observe.dto.data.ps.common.TripDto.class, "routeLogbook", 1);
|
|
| 92 | + List<?> data = assertCreateTrip(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 93 | + fr.ird.observe.dto.data.ps.common.TripDto.class, "routeLogbook", 1);
|
|
| 93 | 94 | Assert.assertNotNull(data);
|
| 94 | 95 | }
|
| 95 | 96 | {
|
| 96 | - Map<String, Object> data = assertTrip0(TripService.class,
|
|
| 97 | - fr.ird.observe.dto.data.ps.common.TripDto.class, "all");
|
|
| 97 | + Map<String, Object> data = assertCreateTrip0(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 98 | + fr.ird.observe.dto.data.ps.common.TripDto.class, "all");
|
|
| 98 | 99 | Assert.assertNotNull(data);
|
| 99 | 100 | }
|
| 100 | 101 | } finally {
|
| ... | ... | @@ -102,28 +103,55 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 102 | 103 | }
|
| 103 | 104 | }
|
| 104 | 105 | |
| 106 | + @Test
|
|
| 107 | + @CopyDatabaseConfiguration
|
|
| 108 | + @DatabaseNameConfiguration(DatabaseName.referential)
|
|
| 109 | + public void updatePsTrip() throws InvalidDataException {
|
|
| 110 | + TOPIA_TEST_CLASS_RESOURCE.getServiceInitializerConfig().setValidationMode(DataSourceValidationMode.NONE);
|
|
| 111 | + Map<?, ?> tripMap = null;
|
|
| 112 | + {
|
|
| 113 | + tripMap = assertCreateTrip0(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 114 | + fr.ird.observe.dto.data.ps.common.TripDto.class, "gearUseFeatures");
|
|
| 115 | + Assert.assertNotNull(tripMap);
|
|
| 116 | + }
|
|
| 117 | + Objects.requireNonNull(tripMap);
|
|
| 118 | + String tripId = (String) tripMap.get(ToolkitId.PROPERTY_TOOLKIT_TOPIA_ID);
|
|
| 119 | + int exceptedRouteCount = 2;
|
|
| 120 | + {
|
|
| 121 | + List<?> data = assertUpdateTrip(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 122 | + fr.ird.observe.dto.data.ps.common.TripDto.class, Objects.requireNonNull(tripId), "routeObs", exceptedRouteCount);
|
|
| 123 | + Assert.assertNotNull(data);
|
|
| 124 | + }
|
|
| 125 | + {
|
|
| 126 | + List<?> data = assertUpdateTrip(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 127 | + fr.ird.observe.dto.data.ps.common.TripDto.class, Objects.requireNonNull(tripId), "routeObs", 2*exceptedRouteCount);
|
|
| 128 | + Assert.assertNotNull(data);
|
|
| 129 | + }
|
|
| 130 | + //FIXME Add more test for update https://gitlab.com/ultreiaio/ird-observe/-/issues/2171
|
|
| 131 | + }
|
|
| 132 | + |
|
| 105 | 133 | @Test
|
| 106 | 134 | @CopyDatabaseConfiguration
|
| 107 | 135 | public void createLlTrip() throws InvalidDataException {
|
| 108 | 136 | TOPIA_TEST_CLASS_RESOURCE.getServiceInitializerConfig().setValidationMode(DataSourceValidationMode.NONE);
|
| 109 | 137 | {
|
| 110 | - List<?> data = assertTrip(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 111 | - fr.ird.observe.dto.data.ll.common.TripDto.class, "gearUseFeatures", 1);
|
|
| 138 | + List<?> data = assertCreateTrip(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 139 | + fr.ird.observe.dto.data.ll.common.TripDto.class, "gearUseFeatures", 1);
|
|
| 112 | 140 | Assert.assertNotNull(data);
|
| 113 | 141 | }
|
| 114 | 142 | {
|
| 115 | - List<?> data = assertTrip(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 116 | - fr.ird.observe.dto.data.ll.common.TripDto.class, "activityObs", 2);
|
|
| 143 | + List<?> data = assertCreateTrip(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 144 | + fr.ird.observe.dto.data.ll.common.TripDto.class, "activityObs", 2);
|
|
| 117 | 145 | Assert.assertNotNull(data);
|
| 118 | 146 | }
|
| 119 | 147 | {
|
| 120 | - List<?> data = assertTrip(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 121 | - fr.ird.observe.dto.data.ll.common.TripDto.class, "activityLogbook", 2);
|
|
| 148 | + List<?> data = assertCreateTrip(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 149 | + fr.ird.observe.dto.data.ll.common.TripDto.class, "activityLogbook", 2);
|
|
| 122 | 150 | Assert.assertNotNull(data);
|
| 123 | 151 | }
|
| 124 | 152 | {
|
| 125 | - Map<String, Object> data = assertTrip0(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 126 | - fr.ird.observe.dto.data.ll.common.TripDto.class, "all");
|
|
| 153 | + Map<String, Object> data = assertCreateTrip0(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 154 | + fr.ird.observe.dto.data.ll.common.TripDto.class, "all");
|
|
| 127 | 155 | Assert.assertNotNull(data);
|
| 128 | 156 | }
|
| 129 | 157 | }
|
| ... | ... | @@ -132,8 +160,8 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 132 | 160 | @CopyDatabaseConfiguration
|
| 133 | 161 | public void createPsTripLinks() throws InvalidDataException {
|
| 134 | 162 | TOPIA_TEST_CLASS_RESOURCE.getServiceInitializerConfig().setValidationMode(DataSourceValidationMode.NONE);
|
| 135 | - Map<String, Object> data = assertTrip0(TripService.class,
|
|
| 136 | - fr.ird.observe.dto.data.ps.common.TripDto.class, "links");
|
|
| 163 | + Map<String, Object> data = assertCreateTrip0(fr.ird.observe.services.service.data.ps.common.TripService.class,
|
|
| 164 | + fr.ird.observe.dto.data.ps.common.TripDto.class, "links");
|
|
| 137 | 165 | Assert.assertNotNull(data);
|
| 138 | 166 | }
|
| 139 | 167 | |
| ... | ... | @@ -141,13 +169,13 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 141 | 169 | @CopyDatabaseConfiguration
|
| 142 | 170 | public void createLlTripLinks() throws InvalidDataException {
|
| 143 | 171 | TOPIA_TEST_CLASS_RESOURCE.getServiceInitializerConfig().setValidationMode(DataSourceValidationMode.NONE);
|
| 144 | - Map<String, Object> data = assertTrip0(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 145 | - fr.ird.observe.dto.data.ll.common.TripDto.class, "links");
|
|
| 172 | + Map<String, Object> data = assertCreateTrip0(fr.ird.observe.services.service.data.ll.common.TripService.class,
|
|
| 173 | + fr.ird.observe.dto.data.ll.common.TripDto.class, "links");
|
|
| 146 | 174 | Assert.assertNotNull(data);
|
| 147 | 175 | }
|
| 148 | 176 | |
| 149 | - protected List<?> assertTrip(Class<?> serviceType, Class<? extends DataDto> dtoType, String classifier, int expectedCount) throws InvalidDataException {
|
|
| 150 | - Map<String, Object> resultObject = assertTrip0(serviceType, dtoType, classifier);
|
|
| 177 | + protected List<?> assertCreateTrip(Class<?> serviceType, Class<? extends DataDto> dtoType, String classifier, int expectedCount) throws InvalidDataException {
|
|
| 178 | + Map<String, Object> resultObject = assertCreateTrip0(serviceType, dtoType, classifier);
|
|
| 151 | 179 | Assert.assertNotNull(resultObject);
|
| 152 | 180 | |
| 153 | 181 | List<?> data = (List<?>) resultObject.get(classifier);
|
| ... | ... | @@ -156,7 +184,8 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 156 | 184 | return data;
|
| 157 | 185 | }
|
| 158 | 186 | |
| 159 | - protected Map<String, Object> assertTrip0(Class<?> serviceType, Class<? extends DataDto> dtoType, String classifier) throws InvalidDataException {
|
|
| 187 | + |
|
| 188 | + protected Map<String, Object> assertCreateTrip0(Class<?> serviceType, Class<? extends DataDto> dtoType, String classifier) throws InvalidDataException {
|
|
| 160 | 189 | String json = fixtures.loadContent(serviceType, classifier);
|
| 161 | 190 | ToolkitTreeNodeStates result = fixtures.testCreate(service, dtoType, json);
|
| 162 | 191 | String content = result.getState("content");
|
| ... | ... | @@ -166,4 +195,25 @@ public class DataEntityServiceLocalWriteTest extends GeneratedDataEntityServiceL |
| 166 | 195 | return resultObject;
|
| 167 | 196 | |
| 168 | 197 | }
|
| 198 | + |
|
| 199 | + protected List<?> assertUpdateTrip(Class<?> serviceType, Class<? extends DataDto> dtoType, String id, String classifier, int expectedCount) throws InvalidDataException {
|
|
| 200 | + Map<String, Object> resultObject = assertUpdateTrip0(serviceType, dtoType, id, classifier);
|
|
| 201 | + Assert.assertNotNull(resultObject);
|
|
| 202 | + |
|
| 203 | + List<?> data = (List<?>) resultObject.get(classifier);
|
|
| 204 | + Assert.assertNotNull(data);
|
|
| 205 | + Assert.assertEquals(expectedCount, data.size());
|
|
| 206 | + return data;
|
|
| 207 | + }
|
|
| 208 | + |
|
| 209 | + protected Map<String, Object> assertUpdateTrip0(Class<?> serviceType, Class<? extends DataDto> dtoType, String id, String classifier) throws InvalidDataException {
|
|
| 210 | + String json = fixtures.loadContent(serviceType, classifier);
|
|
| 211 | + ToolkitTreeNodeStates result = fixtures.testUpdate(service, dtoType, id, json);
|
|
| 212 | + String content = result.getState("content");
|
|
| 213 | + Assert.assertNotNull(content);
|
|
| 214 | + @SuppressWarnings("unchecked") Map<String, Object> resultObject = (Map<String, Object>) fixtures.fromJsonList(content).get(0);
|
|
| 215 | + Assert.assertNotNull(resultObject);
|
|
| 216 | + return resultObject;
|
|
| 217 | + |
|
| 218 | + }
|
|
| 169 | 219 | } |
| ... | ... | @@ -378,7 +378,7 @@ public class DataEntityServiceFixtures extends GeneratedDataEntityServiceFixture |
| 378 | 378 | }
|
| 379 | 379 | try {
|
| 380 | 380 | String content = loadFixture(module, subModule, dtoType, "content.json");
|
| 381 | - testUpdate(service, dtoType, content);
|
|
| 381 | + testUpdate(service, dtoType, null, content);
|
|
| 382 | 382 | } catch (IOException e) {
|
| 383 | 383 | log.warn(String.format("No fixture for %s", dtoType));
|
| 384 | 384 | } catch (InvalidDataException e) {
|
| ... | ... | @@ -404,11 +404,14 @@ public class DataEntityServiceFixtures extends GeneratedDataEntityServiceFixture |
| 404 | 404 | return getResult;
|
| 405 | 405 | }
|
| 406 | 406 | |
| 407 | - public ToolkitTreeNodeStates testUpdate(DataEntityService service, Class<? extends DataDto> dtoType, String content) throws InvalidDataException {
|
|
| 407 | + public ToolkitTreeNodeStates testUpdate(DataEntityService service, Class<? extends DataDto> dtoType, String id, String content) throws InvalidDataException {
|
|
| 408 | 408 | log.debug(String.format("for type: %s", dtoType.getName()));
|
| 409 | 409 | Pair<String, List<Object>> result = JsonHelper.removeAndCollectProperties(gson, content, ToolkitId.PROPERTY_TOOLKIT_TOPIA_ID, ToolkitId.PROPERTY_TOOLKIT_CREATE_DATE, ToolkitId.PROPERTY_TOOLKIT_LAST_UPDATE_DATE);
|
| 410 | 410 | content = result.getKey();
|
| 411 | - String id = (String) result.getValue().get(0);
|
|
| 411 | + if (id==null) {
|
|
| 412 | + |
|
| 413 | + id = (String) result.getValue().get(0);
|
|
| 414 | + }
|
|
| 412 | 415 | ToolkitId actual = service.update(dtoType, Objects.requireNonNull(id), content);
|
| 413 | 416 | Assert.assertNotNull(actual);
|
| 414 | 417 | Assert.assertEquals(id, actual.getTopiaId());
|
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <parent>
|
| 24 | 24 | <groupId>io.ultreia.maven</groupId>
|
| 25 | 25 | <artifactId>pom</artifactId>
|
| 26 | - <version>2022.21</version>
|
|
| 26 | + <version>2022.22</version>
|
|
| 27 | 27 | </parent>
|
| 28 | 28 | <groupId>fr.ird.observe</groupId>
|
| 29 | 29 | <artifactId>ird-observe</artifactId>
|
| ... | ... | @@ -155,7 +155,7 @@ |
| 155 | 155 | <!-- build timestamp configuration -->
|
| 156 | 156 | <maven.build.timestamp.format>dd/MM/yyyy HH:mm z</maven.build.timestamp.format>
|
| 157 | 157 | <buildDate>${maven.build.timestamp}</buildDate>
|
| 158 | - <lib.version.toolkit>6.0.2</lib.version.toolkit>
|
|
| 158 | + <lib.version.toolkit>6.0.3</lib.version.toolkit>
|
|
| 159 | 159 | <lib.version.ognl>3.1.29</lib.version.ognl>
|
| 160 | 160 | <!--can't use 1.4.197 (date has changed + blob also)-->
|
| 161 | 161 | <lib.version.h2>1.4.196</lib.version.h2>
|
| ... | ... | @@ -29,7 +29,7 @@ sh default-migrate-server-v7.sh |
| 29 | 29 | |
| 30 | 30 | ## Optimize v9 server configuration file
|
| 31 | 31 | |
| 32 | -v9 **security.yml** file can be optimize.
|
|
| 32 | +v9 **security.yml** file can be optimized.
|
|
| 33 | 33 | |
| 34 | 34 | Run the script **optimize-server-v9.sh** for this purpose.
|
| 35 | 35 |
| ... | ... | @@ -90,7 +90,7 @@ public class ServerConfig extends GeneratedServerConfig implements CleanTemporar |
| 90 | 90 | fakeConfig.initFirst();
|
| 91 | 91 | |
| 92 | 92 | // Now that common files are ready, starts a normal configuration without system file and without migration possible
|
| 93 | - ApplicationConfigInit realInit = ApplicationConfigInit.forAllScopesWithout(ApplicationConfigScope.HOME, ApplicationConfigScope.ENV, ApplicationConfigScope.SYSTEM)
|
|
| 93 | + ApplicationConfigInit realInit = ApplicationConfigInit.forAllScopesWithout(ApplicationConfigScope.HOME, ApplicationConfigScope.ENV, ApplicationConfigScope.SYSTEM)
|
|
| 94 | 94 | .addDefaults(ServerConfigOption.CONTEXT_PATH.getKey(), contextPath);
|
| 95 | 95 | |
| 96 | 96 | ServerConfig config = new ServerConfig(setInstanceExtraConfigDirectory(setConfigFileName(realInit)));
|
| ... | ... | @@ -133,22 +133,22 @@ public class ServerConfig extends GeneratedServerConfig implements CleanTemporar |
| 133 | 133 | }
|
| 134 | 134 | |
| 135 | 135 | public void initFirst() {
|
| 136 | - log.info("Starts to init ObServe fake server configuration (to generate default directories and common files...");
|
|
| 136 | + log.info("Starts to init ObServe fake server configuration (to generate default directories and common files...)");
|
|
| 137 | 137 | |
| 138 | 138 | parse();
|
| 139 | 139 | |
| 140 | 140 | Path baseDirectory = getCommonConfigDirectory().toPath();
|
| 141 | - createDirectories(baseDirectory, "Impossible de créer le répertoire principal de l'application (%s)");
|
|
| 141 | + createDirectories(baseDirectory, "Could not create application main directory (%s)");
|
|
| 142 | 142 | |
| 143 | 143 | File extraConfigFile = get().getExtraConfigFile();
|
| 144 | 144 | if (Files.notExists(extraConfigFile.toPath())) {
|
| 145 | 145 | log.info(String.format("Save common configuration file to: %s", extraConfigFile));
|
| 146 | - ConfigHelper.save(get(), extraConfigFile, new String[0], ServerResources.CONFIG, options());
|
|
| 146 | + ConfigHelper.save(get(), extraConfigFile, new String[0], ServerResources.APPLICATION_CONFIGURATION, options());
|
|
| 147 | 147 | }
|
| 148 | 148 | |
| 149 | 149 | File log4jConfigurationFile = getCommonLog4jConfigurationFile();
|
| 150 | 150 | if (!log4jConfigurationFile.exists()) {
|
| 151 | - ServerResources.LOG_CONFIGURATION_FILE.copyResource(log4jConfigurationFile);
|
|
| 151 | + ServerResources.LOG_CONFIGURATION.copyResource(log4jConfigurationFile);
|
|
| 152 | 152 | log.info(String.format("Generate empty log4j configuration file to: %s", log4jConfigurationFile));
|
| 153 | 153 | }
|
| 154 | 154 | }
|
| ... | ... | @@ -160,11 +160,11 @@ public class ServerConfig extends GeneratedServerConfig implements CleanTemporar |
| 160 | 160 | |
| 161 | 161 | Path baseDirectory = getBaseDirectory().toPath();
|
| 162 | 162 | log.info(getConfigurationDescription());
|
| 163 | - createDirectories(baseDirectory, "Impossible de créer le répertoire principal de l'application (%s)");
|
|
| 163 | + createDirectories(baseDirectory, "Could not create application instance directory (%s)");
|
|
| 164 | 164 | |
| 165 | 165 | File extraConfigFile = get().getExtraConfigFile();
|
| 166 | 166 | if (Files.notExists(extraConfigFile.toPath())) {
|
| 167 | - boolean generated = ServerResources.CONFIG.copyResource(getCommonConfigurationFile().toPath(), extraConfigFile);
|
|
| 167 | + boolean generated = ServerResources.APPLICATION_CONFIGURATION.copyResource(getCommonConfigurationFile().toPath(), extraConfigFile);
|
|
| 168 | 168 | if (generated) {
|
| 169 | 169 | log.info(String.format("Generate empty configuration file to: %s", extraConfigFile));
|
| 170 | 170 | } else {
|
| ... | ... | @@ -173,7 +173,7 @@ public class ServerConfig extends GeneratedServerConfig implements CleanTemporar |
| 173 | 173 | }
|
| 174 | 174 | |
| 175 | 175 | Path temporaryDirectory = getTemporaryDirectory().toPath();
|
| 176 | - createDirectories(temporaryDirectory, "Impossible de créer le répertoire temporaire (%s)");
|
|
| 176 | + createDirectories(temporaryDirectory, "Could not create temporary directory (%s)");
|
|
| 177 | 177 | |
| 178 | 178 | File securityConfigurationFile = getSecurityConfigurationFile();
|
| 179 | 179 | if (!securityConfigurationFile.exists()) {
|
| ... | ... | @@ -181,7 +181,7 @@ public class ServerConfig extends GeneratedServerConfig implements CleanTemporar |
| 181 | 181 | if (strict && !commonSecurityConfigurationFile.exists()) {
|
| 182 | 182 | throw new IllegalStateException(String.format("Can not start application. Could not find security.yml file.\n\nPlease add it to one of this places:\n\t%s\n\t%s", commonSecurityConfigurationFile, securityConfigurationFile));
|
| 183 | 183 | }
|
| 184 | - boolean generated = ServerResources.SECURITY.copyResource(commonSecurityConfigurationFile.toPath(), securityConfigurationFile);
|
|
| 184 | + boolean generated = ServerResources.SECURITY_CONFIGURATION.setStrict(strict).copyResource(commonSecurityConfigurationFile.toPath(), securityConfigurationFile);
|
|
| 185 | 185 | if (generated) {
|
| 186 | 186 | log.info("Generate default security.yml");
|
| 187 | 187 | } else {
|
| ... | ... | @@ -192,28 +192,37 @@ public class ServerConfig extends GeneratedServerConfig implements CleanTemporar |
| 192 | 192 | log.info("ObServe server configuration init done.");
|
| 193 | 193 | }
|
| 194 | 194 | |
| 195 | + public ReferentialLocale getReferentialLocale() {
|
|
| 196 | + if (referentialLocale == null) {
|
|
| 197 | + referentialLocale = ReferentialLocale.valueOf(getDbLocale());
|
|
| 198 | + }
|
|
| 199 | + return referentialLocale;
|
|
| 200 | + }
|
|
| 201 | + |
|
| 202 | + public String getConfigurationContent() throws IOException {
|
|
| 203 | + Path path = get().getExtraConfigFile().toPath();
|
|
| 204 | + return Files.readString(path);
|
|
| 205 | + }
|
|
| 206 | + |
|
| 207 | + public String getSecurityContent() throws IOException {
|
|
| 208 | + Path path = getSecurityConfigurationFile().toPath();
|
|
| 209 | + return Files.readString(path);
|
|
| 210 | + }
|
|
| 211 | + |
|
| 195 | 212 | private void parse() {
|
| 196 | 213 | try {
|
| 197 | 214 | get().parse();
|
| 198 | 215 | } catch (ArgumentsParserException e) {
|
| 199 | 216 | throw new ObserveWebApplicationConfigInitException("could not parse configuration", e);
|
| 200 | 217 | }
|
| 201 | - |
|
| 202 | 218 | }
|
| 203 | 219 | |
| 204 | 220 | private void initLog() {
|
| 205 | 221 | File logFile = getLog4jConfigurationFile();
|
| 206 | 222 | log.info(String.format("Chargement du fichier de log : %s", logFile));
|
| 207 | - ObserveUtil.loadLogConfiguration(ServerResources.LOG_CONFIGURATION_FILE, getCommonLog4jConfigurationFile().toPath(), logFile.toPath(), this);
|
|
| 223 | + ObserveUtil.loadLogConfiguration(ServerResources.LOG_CONFIGURATION, getCommonLog4jConfigurationFile().toPath(), logFile.toPath(), this);
|
|
| 208 | 224 | log = LogManager.getLogger(ServerConfig.class);
|
| 209 | 225 | log.info(String.format("Configuration des logs chargée depuis le fichier %s", logFile));
|
| 210 | 226 | }
|
| 211 | 227 | |
| 212 | - public ReferentialLocale getReferentialLocale() {
|
|
| 213 | - if (referentialLocale == null) {
|
|
| 214 | - referentialLocale = ReferentialLocale.valueOf(getDbLocale());
|
|
| 215 | - }
|
|
| 216 | - return referentialLocale;
|
|
| 217 | - }
|
|
| 218 | - |
|
| 219 | 228 | } |
| ... | ... | @@ -24,6 +24,10 @@ package fr.ird.observe.server.configuration; |
| 24 | 24 | |
| 25 | 25 | import io.ultreia.java4all.config.ConfigResource;
|
| 26 | 26 | |
| 27 | +import java.io.File;
|
|
| 28 | +import java.nio.file.Files;
|
|
| 29 | +import java.nio.file.Path;
|
|
| 30 | + |
|
| 27 | 31 | /**
|
| 28 | 32 | * Created on 07/12/2021.
|
| 29 | 33 | *
|
| ... | ... | @@ -31,7 +35,33 @@ import io.ultreia.java4all.config.ConfigResource; |
| 31 | 35 | * @since 9.0.0
|
| 32 | 36 | */
|
| 33 | 37 | public class ServerResources {
|
| 34 | - public static final ConfigResource CONFIG = new ConfigResource("/META-INF/configuration/observe-server.conf");
|
|
| 35 | - public static final ConfigResource SECURITY = new ConfigResource("/defaultSecurity.yml");
|
|
| 36 | - public static final ConfigResource LOG_CONFIGURATION_FILE = new ConfigResource("/log.xml");
|
|
| 38 | + public static final ConfigResource APPLICATION_CONFIGURATION = new ConfigResource("/META-INF/configuration/observe-server.conf");
|
|
| 39 | + public static final ConfigResource2 SECURITY_CONFIGURATION = new ConfigResource2("/META-INF/configuration/security.yml");
|
|
| 40 | + public static final ConfigResource LOG_CONFIGURATION = new ConfigResource("/META-INF/configuration/log.xml");
|
|
| 41 | + |
|
| 42 | + static class ConfigResource2 extends ConfigResource {
|
|
| 43 | + |
|
| 44 | + private boolean strict;
|
|
| 45 | + |
|
| 46 | + public ConfigResource2(String location) {
|
|
| 47 | + super(location);
|
|
| 48 | + }
|
|
| 49 | + |
|
| 50 | + public boolean isStrict() {
|
|
| 51 | + return strict;
|
|
| 52 | + }
|
|
| 53 | + |
|
| 54 | + public ConfigResource2 setStrict(boolean strict) {
|
|
| 55 | + this.strict = strict;
|
|
| 56 | + return this;
|
|
| 57 | + }
|
|
| 58 | + |
|
| 59 | + @Override
|
|
| 60 | + public boolean copyResource(Path sharedFile, File file) {
|
|
| 61 | + if (isStrict() && Files.notExists(sharedFile)) {
|
|
| 62 | + throw new IllegalStateException(String.format("You are not allowed to copy this resource: %s", this));
|
|
| 63 | + }
|
|
| 64 | + return super.copyResource(sharedFile, file);
|
|
| 65 | + }
|
|
| 66 | + }
|
|
| 37 | 67 | } |
| ... | ... | @@ -23,8 +23,6 @@ package fr.ird.observe.server.controller; |
| 23 | 23 | */
|
| 24 | 24 | |
| 25 | 25 | import fr.ird.observe.dto.server.InvalidServerModelException;
|
| 26 | -import fr.ird.observe.dto.server.ServerModel;
|
|
| 27 | -import fr.ird.observe.dto.server.ServerModelHelper;
|
|
| 28 | 26 | import fr.ird.observe.server.security.ObserveWebSecurityApplicationContext;
|
| 29 | 27 | import fr.ird.observe.server.security.ObserveWebUserSession;
|
| 30 | 28 | import fr.ird.observe.spi.RenderMarkdown;
|
| ... | ... | @@ -54,7 +52,7 @@ public class AdminController extends ObserveWebMotionController { |
| 54 | 52 | public RenderContent configuration() throws IOException {
|
| 55 | 53 | StringBuilder builder = new StringBuilder();
|
| 56 | 54 | builder.append("\n## Configuration\n");
|
| 57 | - String content = getApplicationConfiguration().getConfigurationDescription();
|
|
| 55 | + String content = getApplicationConfiguration().getConfigurationContent();
|
|
| 58 | 56 | builder.append(String.format("\n```properties\n%s\n```", content));
|
| 59 | 57 | return toHtml(RenderMarkdown.renderContent(builder.toString()));
|
| 60 | 58 | }
|
| ... | ... | @@ -77,8 +75,7 @@ public class AdminController extends ObserveWebMotionController { |
| 77 | 75 | builder.append("\n## Fichier de définition du sécurité\n");
|
| 78 | 76 | File securityConfigurationFile = getApplicationConfiguration().getSecurityConfigurationFile();
|
| 79 | 77 | builder.append(String.format("\nEmplacement : %s\n", securityConfigurationFile));
|
| 80 | - ServerModel securityModel = ServerModelHelper.load(securityConfigurationFile);
|
|
| 81 | - String content = ServerModelHelper.toString(securityModel);
|
|
| 78 | + String content = getApplicationConfiguration().getSecurityContent();
|
|
| 82 | 79 | builder.append(String.format("\n```yaml\n%s\n```", content));
|
| 83 | 80 | return toHtml(RenderMarkdown.renderContent(builder.toString()));
|
| 84 | 81 | }
|
| ... | ... | @@ -26,8 +26,6 @@ import fr.ird.observe.dto.db.DataSourceApiAccess; |
| 26 | 26 | import fr.ird.observe.dto.db.configuration.ObserveDataSourceConnection;
|
| 27 | 27 | import fr.ird.observe.dto.referential.ReferentialLocale;
|
| 28 | 28 | import fr.ird.observe.dto.server.ServerModel;
|
| 29 | -import fr.ird.observe.dto.server.security.InvalidApiAccessException;
|
|
| 30 | -import fr.ird.observe.dto.server.security.InvalidAuthenticationTokenException;
|
|
| 31 | 29 | import fr.ird.observe.server.configuration.ServerConfig;
|
| 32 | 30 | import io.ultreia.java4all.util.Version;
|
| 33 | 31 | |
| ... | ... | @@ -38,7 +36,15 @@ import java.util.Collection; |
| 38 | 36 | import java.util.Locale;
|
| 39 | 37 | |
| 40 | 38 | /**
|
| 41 | - * Pour conserver les données applicatives liée à la sécurité (principale le cache des utilisateurs connectés).
|
|
| 39 | + * Application security context.
|
|
| 40 | + * <p>
|
|
| 41 | + * Manages
|
|
| 42 | + *
|
|
| 43 | + * <ul>
|
|
| 44 | + * <li>a cache of configuration ({@link #configurationCache}, to init a new session from an available configuration)</li>
|
|
| 45 | + * <li>a cache of session ({@link #authenticateCache} to keep authenticated session)</li>
|
|
| 46 | + * </ul>
|
|
| 47 | + *
|
|
| 42 | 48 | * <p>
|
| 43 | 49 | * Created on 30/08/15.
|
| 44 | 50 | *
|
| ... | ... | @@ -46,17 +52,14 @@ import java.util.Locale; |
| 46 | 52 | */
|
| 47 | 53 | public class ObserveWebSecurityApplicationContext implements Closeable {
|
| 48 | 54 | |
| 49 | - /**
|
|
| 50 | - * Cache of session.
|
|
| 51 | - */
|
|
| 52 | - protected final ObserveWebSecuritySessionCache authenticateCache;
|
|
| 53 | - |
|
| 54 | 55 | /**
|
| 55 | 56 | * Cache of available configurations.
|
| 56 | - *
|
|
| 57 | - * @see ObserveWebSecurityConfigCache
|
|
| 58 | 57 | */
|
| 59 | 58 | protected final ObserveWebSecurityConfigCache configurationCache;
|
| 59 | + /**
|
|
| 60 | + * Cache of session.
|
|
| 61 | + */
|
|
| 62 | + protected final ObserveWebSecuritySessionCache authenticateCache;
|
|
| 60 | 63 | |
| 61 | 64 | public ObserveWebSecurityApplicationContext(ServerConfig configuration) {
|
| 62 | 65 | this.authenticateCache = new ObserveWebSecuritySessionCache(configuration.getSessionExpirationDelay());
|
| ... | ... | @@ -64,7 +67,7 @@ public class ObserveWebSecurityApplicationContext implements Closeable { |
| 64 | 67 | }
|
| 65 | 68 | |
| 66 | 69 | public synchronized void init(Path temporaryDirectory, ServerModel serverModel, Version modelVersion) {
|
| 67 | - authenticateCache.removeAllSessions();
|
|
| 70 | + authenticateCache.close();
|
|
| 68 | 71 | configurationCache.load(serverModel, modelVersion, temporaryDirectory);
|
| 69 | 72 | }
|
| 70 | 73 | |
| ... | ... | @@ -74,8 +77,8 @@ public class ObserveWebSecurityApplicationContext implements Closeable { |
| 74 | 77 | |
| 75 | 78 | public ObserveWebUserSession newConfigurationSession(ObserveWebUserSession anonymousSession, String userLogin, String userPassword, String optionalDatabaseName) {
|
| 76 | 79 | Locale locale = anonymousSession.getApplicationLocale();
|
| 77 | - ObserveWebSecurityConfigCacheKey configCacheKey = configurationCache.getEntry(locale, userLogin, optionalDatabaseName, userPassword);
|
|
| 78 | - return anonymousSession.toConfigurationSession(configCacheKey);
|
|
| 80 | + ObserveWebSecurityConfigCacheValue cacheValue = configurationCache.getValue(locale, userLogin, optionalDatabaseName, userPassword);
|
|
| 81 | + return anonymousSession.toConfigurationSession(cacheValue);
|
|
| 79 | 82 | }
|
| 80 | 83 | |
| 81 | 84 | public ObserveWebUserSession registerAuthenticatedSession(ObserveWebUserSession configurationSession, ObserveDataSourceConnection connection) {
|
| ... | ... | @@ -89,14 +92,7 @@ public class ObserveWebSecurityApplicationContext implements Closeable { |
| 89 | 92 | }
|
| 90 | 93 | |
| 91 | 94 | public ObserveWebUserSession getSession(Locale locale, String authenticationToken, DataSourceApiAccess requestApiAccess) {
|
| 92 | - ObserveWebUserSession session = authenticateCache.getSessionIfPresent(authenticationToken);
|
|
| 93 | - if (session == null) {
|
|
| 94 | - throw new InvalidAuthenticationTokenException(locale, authenticationToken);
|
|
| 95 | - }
|
|
| 96 | - if (session.rejectApiAccess(requestApiAccess)) {
|
|
| 97 | - throw new InvalidApiAccessException(locale, requestApiAccess, session.getUserPermission().getApiAccess());
|
|
| 98 | - }
|
|
| 99 | - return session;
|
|
| 95 | + return authenticateCache.getSession(locale, authenticationToken, requestApiAccess);
|
|
| 100 | 96 | }
|
| 101 | 97 | |
| 102 | 98 | public void invalidateAuthenticationToken(String authenticationToken) {
|
| ... | ... | @@ -22,7 +22,6 @@ package fr.ird.observe.server.security; |
| 22 | 22 | * #L%
|
| 23 | 23 | */
|
| 24 | 24 | |
| 25 | -import com.google.common.base.Strings;
|
|
| 26 | 25 | import fr.ird.observe.dto.db.configuration.ObserveDataSourceConfiguration;
|
| 27 | 26 | import fr.ird.observe.dto.db.configuration.topia.ObserveDataSourceConfigurationTopiaPG;
|
| 28 | 27 | import fr.ird.observe.dto.server.ServerDatabase;
|
| ... | ... | @@ -35,6 +34,7 @@ import fr.ird.observe.dto.server.security.UnknownObserveWebUserException; |
| 35 | 34 | import fr.ird.observe.dto.server.security.UnknownObserveWebUserForDatabaseException;
|
| 36 | 35 | import fr.ird.observe.dto.server.security.UserLoginNotFoundException;
|
| 37 | 36 | import fr.ird.observe.dto.server.security.UserPasswordNotFoundException;
|
| 37 | +import io.ultreia.java4all.lang.Strings;
|
|
| 38 | 38 | import io.ultreia.java4all.util.Version;
|
| 39 | 39 | import org.apache.logging.log4j.LogManager;
|
| 40 | 40 | import org.apache.logging.log4j.Logger;
|
| ... | ... | @@ -48,7 +48,11 @@ import java.util.TreeMap; |
| 48 | 48 | import java.util.TreeSet;
|
| 49 | 49 | |
| 50 | 50 | /**
|
| 51 | - * Cache of security config.
|
|
| 51 | + * Cache of security config, build from the {@code security.yml} file.
|
|
| 52 | + * <p>
|
|
| 53 | + * The method {@link #load(ServerModel, Version, Path)} load once for all the security model in the {@link #cache}.
|
|
| 54 | + * <p>
|
|
| 55 | + * After that, to get a configuration, use the method {@link #getKey(String, String)}.
|
|
| 52 | 56 | * <p>
|
| 53 | 57 | * Created on 19/12/2021.
|
| 54 | 58 | *
|
| ... | ... | @@ -60,25 +64,32 @@ public class ObserveWebSecurityConfigCache { |
| 60 | 64 | private static final Logger log = LogManager.getLogger(ObserveWebSecurityConfigCache.class);
|
| 61 | 65 | |
| 62 | 66 | /**
|
| 63 | - * Le cache des configurations disponibles pour les couple (utilisateur#base) connus du système.
|
|
| 67 | + * Available configurations indexed by the key {@code login--databaseName}, values of configurations.
|
|
| 64 | 68 | *
|
| 65 | - * @see #getUserKey(String, String)
|
|
| 69 | + * @see #getKey(String, String) to get a cache key
|
|
| 70 | + */
|
|
| 71 | + protected final Map<String, ObserveWebSecurityConfigCacheValue> cache;
|
|
| 72 | + /**
|
|
| 73 | + * Available logins (used to check if login exists)
|
|
| 66 | 74 | */
|
| 67 | - protected final Map<String, ObserveWebSecurityConfigCacheKey> cache;
|
|
| 68 | 75 | protected final Set<String> availableUserLogin;
|
| 69 | 76 | /**
|
| 70 | - * Le nom de la base par défaut à utiliser si elle n'est pas spécifiée.
|
|
| 77 | + * Default database name (defined in {@code security.yml}), used if non database is given in a request).
|
|
| 71 | 78 | *
|
| 72 | 79 | * @see ServerModel#getDefaultDatabase()
|
| 73 | 80 | */
|
| 74 | 81 | protected String defaultDatabaseName;
|
| 75 | 82 | |
| 83 | + protected static String getKey(String userLogin, String databaseName) {
|
|
| 84 | + return userLogin + "--" + databaseName;
|
|
| 85 | + }
|
|
| 86 | + |
|
| 76 | 87 | public ObserveWebSecurityConfigCache() {
|
| 77 | 88 | this.cache = new TreeMap<>();
|
| 78 | 89 | this.availableUserLogin = new TreeSet<>();
|
| 79 | 90 | }
|
| 80 | 91 | |
| 81 | - public void load(ServerModel serverModel, Version modelVersion, Path temporaryDirectory) {
|
|
| 92 | + protected void load(ServerModel serverModel, Version modelVersion, Path temporaryDirectory) {
|
|
| 82 | 93 | cache.clear();
|
| 83 | 94 | availableUserLogin.clear();
|
| 84 | 95 | |
| ... | ... | @@ -95,7 +106,7 @@ public class ObserveWebSecurityConfigCache { |
| 95 | 106 | String jdbcUrl = database.getUrl();
|
| 96 | 107 | String login = role.getLogin();
|
| 97 | 108 | String password = role.getPassword();
|
| 98 | - String userKey = getUserKey(serverUser.getLogin(), database.getName());
|
|
| 109 | + String userKey = getKey(serverUser.getLogin(), database.getName());
|
|
| 99 | 110 | |
| 100 | 111 | // Create DataSourceConfiguration
|
| 101 | 112 | ObserveDataSourceConfiguration configuration = ObserveDataSourceConfigurationTopiaPG.create(
|
| ... | ... | @@ -108,17 +119,18 @@ public class ObserveWebSecurityConfigCache { |
| 108 | 119 | true,
|
| 109 | 120 | modelVersion);
|
| 110 | 121 | configuration.setTemporaryDirectory(temporaryDirectory);
|
| 122 | + ObserveWebSecurityConfigCacheValue value = new ObserveWebSecurityConfigCacheValue(serverUser, serverUserPermission, configuration);
|
|
| 111 | 123 | log.info(String.format("Creates data source configuration for userKey %s : %s", userKey, configuration));
|
| 112 | - cache.put(userKey, new ObserveWebSecurityConfigCacheKey(serverUser, serverUserPermission, configuration));
|
|
| 124 | + cache.put(userKey, value);
|
|
| 113 | 125 | }
|
| 114 | 126 | }
|
| 115 | 127 | }
|
| 116 | 128 | |
| 117 | - public ObserveWebSecurityConfigCacheKey getEntry(Locale locale, String userLogin, String databaseName, String userPassword) {
|
|
| 118 | - if (Strings.isNullOrEmpty(userLogin)) {
|
|
| 129 | + protected ObserveWebSecurityConfigCacheValue getValue(Locale locale, String userLogin, String databaseName, String userPassword) {
|
|
| 130 | + if (Strings.isEmpty(userLogin)) {
|
|
| 119 | 131 | throw new UserLoginNotFoundException(locale);
|
| 120 | 132 | }
|
| 121 | - if (Strings.isNullOrEmpty(userPassword)) {
|
|
| 133 | + if (Strings.isEmpty(userPassword)) {
|
|
| 122 | 134 | throw new UserPasswordNotFoundException(locale);
|
| 123 | 135 | }
|
| 124 | 136 | if (!availableUserLogin.contains(userLogin)) {
|
| ... | ... | @@ -127,21 +139,18 @@ public class ObserveWebSecurityConfigCache { |
| 127 | 139 | if (databaseName == null) {
|
| 128 | 140 | databaseName = defaultDatabaseName;
|
| 129 | 141 | }
|
| 130 | - String userKey = getUserKey(userLogin, databaseName);
|
|
| 131 | - log.info(String.format("Try to find data source configuration for: %s", userKey));
|
|
| 132 | - ObserveWebSecurityConfigCacheKey configCacheKey = cache.get(userKey);
|
|
| 133 | - if (configCacheKey == null) {
|
|
| 142 | + String cacheKey = getKey(userLogin, databaseName);
|
|
| 143 | + log.info(String.format("Try to find data source configuration for: %s", cacheKey));
|
|
| 144 | + ObserveWebSecurityConfigCacheValue cacheValue = cache.get(cacheKey);
|
|
| 145 | + if (cacheValue == null) {
|
|
| 134 | 146 | throw new UnknownObserveWebUserForDatabaseException(locale, databaseName, userLogin);
|
| 135 | 147 | }
|
| 136 | - ServerUser user = configCacheKey.getServerUser();
|
|
| 148 | + ServerUser user = cacheValue.getServerUser();
|
|
| 149 | + //FIXME In the cache do not keep real password but a hash
|
|
| 137 | 150 | if (!Objects.equals(user.getPassword(), userPassword)) {
|
| 138 | 151 | throw new BadObserveWebUserPasswordException(locale, userLogin);
|
| 139 | 152 | }
|
| 140 | - log.info(String.format("Will use database configuration: %s", configCacheKey.getConfiguration()));
|
|
| 141 | - return configCacheKey;
|
|
| 142 | - }
|
|
| 143 | - |
|
| 144 | - public String getUserKey(String userLogin, String databaseName) {
|
|
| 145 | - return userLogin + "--" + databaseName;
|
|
| 153 | + log.info(String.format("Will use database configuration: %s", cacheValue.getConfiguration()));
|
|
| 154 | + return cacheValue;
|
|
| 146 | 155 | }
|
| 147 | 156 | } |
| ... | ... | @@ -26,21 +26,34 @@ import fr.ird.observe.dto.db.configuration.ObserveDataSourceConfiguration; |
| 26 | 26 | import fr.ird.observe.dto.server.ServerUser;
|
| 27 | 27 | import fr.ird.observe.dto.server.ServerUserPermission;
|
| 28 | 28 | |
| 29 | +import java.util.Objects;
|
|
| 30 | + |
|
| 29 | 31 | /**
|
| 32 | + * Represents a value in the {@link ObserveWebSecurityConfigCache}.
|
|
| 33 | + * <p>
|
|
| 30 | 34 | * Created on 19/12/2021.
|
| 31 | 35 | *
|
| 32 | 36 | * @author Tony Chemit - dev@tchemit.fr
|
| 33 | 37 | * @since 9.0.0
|
| 34 | 38 | */
|
| 35 | -public class ObserveWebSecurityConfigCacheKey {
|
|
| 39 | +public class ObserveWebSecurityConfigCacheValue {
|
|
| 40 | + /**
|
|
| 41 | + * User.
|
|
| 42 | + */
|
|
| 36 | 43 | private final ServerUser serverUser;
|
| 44 | + /**
|
|
| 45 | + * User permission.
|
|
| 46 | + */
|
|
| 37 | 47 | private final ServerUserPermission serverUserPermission;
|
| 48 | + /**
|
|
| 49 | + * Data source configuration.
|
|
| 50 | + */
|
|
| 38 | 51 | private final ObserveDataSourceConfiguration configuration;
|
| 39 | 52 | |
| 40 | - ObserveWebSecurityConfigCacheKey(ServerUser serverUser, ServerUserPermission serverUserPermission, ObserveDataSourceConfiguration configuration) {
|
|
| 41 | - this.serverUser = serverUser;
|
|
| 42 | - this.serverUserPermission = serverUserPermission;
|
|
| 43 | - this.configuration = configuration;
|
|
| 53 | + ObserveWebSecurityConfigCacheValue(ServerUser serverUser, ServerUserPermission serverUserPermission, ObserveDataSourceConfiguration configuration) {
|
|
| 54 | + this.serverUser = Objects.requireNonNull(serverUser);
|
|
| 55 | + this.serverUserPermission = Objects.requireNonNull(serverUserPermission);
|
|
| 56 | + this.configuration = Objects.requireNonNull(configuration);
|
|
| 44 | 57 | }
|
| 45 | 58 | |
| 46 | 59 | public ServerUser getServerUser() {
|
| ... | ... | @@ -25,14 +25,18 @@ package fr.ird.observe.server.security; |
| 25 | 25 | import com.google.common.cache.Cache;
|
| 26 | 26 | import com.google.common.cache.CacheBuilder;
|
| 27 | 27 | import com.google.common.cache.RemovalListener;
|
| 28 | +import fr.ird.observe.dto.db.DataSourceApiAccess;
|
|
| 29 | +import fr.ird.observe.dto.server.security.InvalidApiAccessException;
|
|
| 30 | +import fr.ird.observe.dto.server.security.InvalidAuthenticationTokenException;
|
|
| 28 | 31 | import org.apache.logging.log4j.LogManager;
|
| 29 | 32 | import org.apache.logging.log4j.Logger;
|
| 30 | 33 | |
| 31 | 34 | import java.io.Closeable;
|
| 35 | +import java.util.Locale;
|
|
| 32 | 36 | import java.util.concurrent.TimeUnit;
|
| 33 | 37 | |
| 34 | 38 | /**
|
| 35 | - * Cache of use session.
|
|
| 39 | + * Cache of user session.
|
|
| 36 | 40 | * <p>
|
| 37 | 41 | * Created on 30/08/15.
|
| 38 | 42 | *
|
| ... | ... | @@ -49,30 +53,37 @@ public class ObserveWebSecuritySessionCache implements Closeable { |
| 49 | 53 | |
| 50 | 54 | public ObserveWebSecuritySessionCache(int expireDelay) {
|
| 51 | 55 | this.sessionCache = CacheBuilder.newBuilder()
|
| 52 | - .expireAfterWrite(expireDelay, TimeUnit.MINUTES)
|
|
| 53 | 56 | .expireAfterAccess(expireDelay, TimeUnit.MINUTES)
|
| 54 | - .removalListener((RemovalListener<String, ObserveWebUserSession>) notification -> log.info(String.format("Remove session: %s - %s", notification.getKey(), notification.getValue())))
|
|
| 57 | + .removalListener((RemovalListener<String, ObserveWebUserSession>) notification -> sessionRemoved(notification.getKey()))
|
|
| 55 | 58 | .build();
|
| 56 | 59 | }
|
| 57 | 60 | |
| 58 | - public ObserveWebUserSession getSessionIfPresent(String authenticationToken) {
|
|
| 59 | - return sessionCache.getIfPresent(authenticationToken);
|
|
| 61 | + public ObserveWebUserSession getSession(Locale locale, String authenticationToken, DataSourceApiAccess requestApiAccess) {
|
|
| 62 | + ObserveWebUserSession session = sessionCache.getIfPresent(authenticationToken);
|
|
| 63 | + if (session == null) {
|
|
| 64 | + throw new InvalidAuthenticationTokenException(locale, authenticationToken);
|
|
| 65 | + }
|
|
| 66 | + if (session.rejectApiAccess(requestApiAccess)) {
|
|
| 67 | + throw new InvalidApiAccessException(locale, requestApiAccess, session.getUserPermission().getApiAccess());
|
|
| 68 | + }
|
|
| 69 | + return session;
|
|
| 70 | + |
|
| 60 | 71 | }
|
| 61 | 72 | |
| 62 | 73 | public void registerSession(ObserveWebUserSession session) {
|
| 63 | - String sessionId = session.getAuthenticationToken();
|
|
| 64 | - log.info(String.format("Add session: %s for data source configuration: %s", sessionId, session.getConfiguration()));
|
|
| 65 | - sessionCache.put(sessionId, session);
|
|
| 74 | + String authenticationToken = session.getAuthenticationToken();
|
|
| 75 | + log.info(String.format("Add session: %s for data source configuration: %s", authenticationToken, session.getConfiguration()));
|
|
| 76 | + sessionCache.put(authenticationToken, session);
|
|
| 66 | 77 | }
|
| 67 | 78 | |
| 68 | - public void removeSession(String sessionId) {
|
|
| 69 | - log.info(String.format("Remove session: %s ", sessionId));
|
|
| 70 | - sessionCache.invalidate(sessionId);
|
|
| 79 | + public void removeSession(String authenticationToken) {
|
|
| 80 | + log.info(String.format("Will remove session: %s ", authenticationToken));
|
|
| 81 | + sessionCache.invalidate(authenticationToken);
|
|
| 82 | + sessionRemoved(authenticationToken);
|
|
| 71 | 83 | }
|
| 72 | 84 | |
| 73 | - public void removeAllSessions() {
|
|
| 74 | - log.info("Remove all session");
|
|
| 75 | - sessionCache.invalidateAll();
|
|
| 85 | + public void sessionRemoved(String authenticationToken) {
|
|
| 86 | + log.info(String.format("Session removed: %s ", authenticationToken));
|
|
| 76 | 87 | }
|
| 77 | 88 | |
| 78 | 89 | public Cache<String, ObserveWebUserSession> getSessionCache() {
|
| ... | ... | @@ -81,7 +92,8 @@ public class ObserveWebSecuritySessionCache implements Closeable { |
| 81 | 92 | |
| 82 | 93 | @Override
|
| 83 | 94 | public void close() {
|
| 84 | - removeAllSessions();
|
|
| 95 | + log.info("Remove all session");
|
|
| 96 | + sessionCache.invalidateAll();
|
|
| 85 | 97 | }
|
| 86 | 98 | |
| 87 | 99 | } |
| ... | ... | @@ -186,7 +186,7 @@ public class ObserveWebUserSession implements ObserveDataSourceConfigurationAndC |
| 186 | 186 | return new ObserveWebRequestContext(applicationContext, this, serviceInitializerConfig);
|
| 187 | 187 | }
|
| 188 | 188 | |
| 189 | - public ObserveWebUserSession toConfigurationSession(ObserveWebSecurityConfigCacheKey configCacheKey) {
|
|
| 189 | + public ObserveWebUserSession toConfigurationSession(ObserveWebSecurityConfigCacheValue configCacheKey) {
|
|
| 190 | 190 | return new ObserveWebUserSession(this, configCacheKey.getConfiguration(), configCacheKey.getServerUser(), configCacheKey.getServerUserPermission());
|
| 191 | 191 | }
|
| 192 | 192 |
| 1 | -To deploy new version of pom: mvn deploy
|
|
| 2 | -To install localy: mvn install |
|
| 1 | +Welcome to Observe server
|
|
| 2 | + |
|
| 3 | +## Init root directory
|
|
| 4 | + |
|
| 5 | +By default, server use a special directory to store all his data: ```/var/local/observe-server```
|
|
| 6 | + |
|
| 7 | +The user that run the tomcat instance must be able to read and write in this directory.
|
|
| 8 | + |
|
| 9 | +Please apply the following command with root user, before starting the first instance of v9.
|
|
| 10 | + |
|
| 11 | +```sh
|
|
| 12 | +mkdir -p /var/local/observe-server
|
|
| 13 | +chown -R tomcat:staff /var/local/observe-server
|
|
| 14 | +```
|
|
| 15 | + |
|
| 16 | +TODO Write a nice document for any help with the server |
| ... | ... | @@ -32,7 +32,7 @@ |
| 32 | 32 | </includes>
|
| 33 | 33 | </fileSet>
|
| 34 | 34 | <fileSet>
|
| 35 | - <directory>src/main/resources</directory>
|
|
| 35 | + <directory>src/main/resources/META-INF/configuration</directory>
|
|
| 36 | 36 | <outputDirectory>config</outputDirectory>
|
| 37 | 37 | <includes>
|
| 38 | 38 | <include>log.xml</include>
|
| ... | ... | @@ -53,6 +53,14 @@ |
| 53 | 53 | <include>${applicationName}-${project.version}.war</include>
|
| 54 | 54 | </includes>
|
| 55 | 55 | </fileSet>
|
| 56 | + <fileSet>
|
|
| 57 | + <directory/>
|
|
| 58 | + <outputDirectory/>
|
|
| 59 | + <fileMode>0755</fileMode>
|
|
| 60 | + <includes>
|
|
| 61 | + <include>README.md</include>
|
|
| 62 | + </includes>
|
|
| 63 | + </fileSet>
|
|
| 56 | 64 | <fileSet>
|
| 57 | 65 | <directory>target/classes</directory>
|
| 58 | 66 | <outputDirectory/>
|
| 1 | 1 | server.config.name=Observe web Configuration
|
| 2 | 2 | server.config.option.common.directory.config=Répertoire des configurations partagées
|
| 3 | -server.config.option.common.directory.config.file=Chemin vers le fichier commun de configuration
|
|
| 3 | +server.config.option.common.directory.config.file=Chemin vers le fichier commun de configuration de l'application
|
|
| 4 | 4 | server.config.option.common.directory.config.file.log=Chemin vers le fichier commun de configuration des logs
|
| 5 | 5 | server.config.option.common.directory.config.file.server=Chemin vers le fichier commun de configuration des bases
|
| 6 | 6 | server.config.option.common.directory.instances=Chemin des instances
|
| ... | ... | @@ -16,5 +16,5 @@ server.config.option.instance.locale.referential=La langue du référentiel (fr_ |
| 16 | 16 | server.config.option.instance.security.key=Clé API Admin (À changer)
|
| 17 | 17 | server.config.option.instance.session.maximum.size=Taille maximum de session
|
| 18 | 18 | server.config.option.instance.timeout.http=Temps maximum de tentative de connection http (en millisecondes)
|
| 19 | -server.config.option.instance.timeout.session=Temps maximum d'une session (en minutes)
|
|
| 19 | +server.config.option.instance.timeout.session=Durée de vie d'un jeton d'authentification (en minutes)
|
|
| 20 | 20 | server.config.option.instance.timeout.temporary.files=Nettoyage des fichiers temporaires (en heures) |