1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package fr.cnes.doi.server;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.security.KeyStore;
26 import java.util.List;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.restlet.Application;
30 import org.restlet.Client;
31 import org.restlet.Component;
32 import org.restlet.Context;
33 import org.restlet.Server;
34 import org.restlet.data.LocalReference;
35 import org.restlet.data.Parameter;
36 import org.restlet.data.Protocol;
37 import org.restlet.engine.Engine;
38 import org.restlet.engine.connector.ConnectorHelper;
39 import org.restlet.ext.httpclient4.HttpDOIClientHelper;
40 import org.restlet.representation.Representation;
41 import org.restlet.resource.ClientResource;
42 import org.restlet.routing.Filter;
43 import org.restlet.service.LogService;
44 import org.restlet.service.Service;
45 import org.restlet.util.Series;
46
47 import fr.cnes.doi.application.AdminApplication;
48 import fr.cnes.doi.application.DoiCrossCiteApplication;
49 import fr.cnes.doi.application.DoiMdsApplication;
50 import fr.cnes.doi.client.ClientMDS;
51 import fr.cnes.doi.db.AbstractUserRoleDBHelper;
52 import fr.cnes.doi.exception.AuthenticationAccessException;
53 import fr.cnes.doi.db.model.AuthSystemUser;
54 import fr.cnes.doi.logging.api.DoiLogDataServer;
55 import fr.cnes.doi.logging.business.JsonMessage;
56 import fr.cnes.doi.logging.security.DoiSecurityLogFilter;
57 import fr.cnes.doi.security.RoleAuthorizer;
58 import fr.cnes.doi.settings.Consts;
59 import fr.cnes.doi.settings.DoiSettings;
60 import fr.cnes.doi.settings.EmailSettings;
61 import fr.cnes.doi.settings.JettySettings;
62 import fr.cnes.doi.settings.ProxySettings;
63 import fr.cnes.doi.utils.Utils;
64 import fr.cnes.doi.utils.spec.Requirement;
65 import fr.cnes.doi.plugin.PluginFactory;
66 import static fr.cnes.doi.plugin.Utils.addPath;
67 import fr.cnes.doi.db.IAuthenticationDBHelper;
68 import fr.cnes.doi.exception.ClientMdsException;
69 import static fr.cnes.doi.settings.Consts.USE_FORWARDED_FOR_HEADER;
70
71
72
73
74
75
76
77 public class DoiServer extends Component {
78
79
80
81
82
83 public static final String DEFAULT_SSL_CTX = "org.restlet.engine.ssl.DefaultSslContextFactory";
84
85
86
87 public static final String SSL_CTX_FACTORY = "sslContextFactory";
88
89
90
91 public static final String KEY_STORE_PATH = "keyStorePath";
92
93
94
95 public static final String KEY_STORE_PWD = "keyStorePassword";
96
97
98
99 public static final String KEY_STORE_TYPE = "keyStoreType";
100
101
102
103 public static final String KEY_PWD = "keyPassword";
104
105
106
107 public static final String TRUST_STORE_PATH = "trustStorePath";
108
109
110
111 public static final String TRUST_STORE_PWD = "trustStorePassword";
112
113
114
115 public static final String TRUST_STORE_TYPE = "trustStoreType";
116
117
118
119 public static final String JKS_FILE = "doiServerKey.jks";
120
121
122
123
124 public static final String JKS_DIRECTORY = "jks";
125
126
127
128
129 public static final String MDS_URI = "/mds";
130
131
132
133
134 public static final String CITATION_URI = "/citation";
135
136
137
138
139 public static final String STATUS_URI = "/status";
140
141
142
143
144 public static final String RESTLET_MAX_TOTAL_CONNECTIONS = "maxTotalConnections";
145
146
147
148
149 public static final String RESTLET_MAX_CONNECTIONS_PER_HOST = "maxConnectionsPerHost";
150
151
152
153
154 public static final String DEFAULT_MAX_TOTAL_CONNECTIONS = "-1";
155
156
157
158
159 public static final String DEFAULT_MAX_CONNECTIONS_PER_HOST = "-1";
160
161
162
163
164 private static final Logger LOG = LogManager.getLogger(DoiServer.class.getName());
165
166
167
168
169 private static final String MESSAGE_TPL = "{} : {}";
170
171
172
173
174 private static final String PARAMETERS = "Parameters";
175
176 static {
177 final List<ConnectorHelper<Client>> registeredClients = Engine.getInstance().
178 getRegisteredClients();
179 registeredClients.add(0, new HttpDOIClientHelper(null));
180 }
181
182
183
184
185 private final DoiSettings settings;
186
187
188
189
190
191
192
193
194
195 public DoiServer(final DoiSettings settings) throws ClientMdsException {
196 super();
197 this.settings = settings;
198 startWithProxy();
199 }
200
201
202
203
204 private void initLogServices() {
205 LOG.traceEntry();
206
207 final LogService logServiceApplication = new DoiLogDataServer(Utils.HTTP_LOGGER_NAME, true);
208 this.getServices().add(logServiceApplication);
209
210 final Service logServiceSecurity = new LogService(true) {
211
212
213
214
215
216
217
218
219 @Override
220 public Filter createInboundFilter(final Context context) {
221 return new DoiSecurityLogFilter();
222 }
223 };
224 this.getServices().add(logServiceSecurity);
225 LOG.traceExit();
226 }
227
228
229
230
231 @Requirement(reqId = Requirement.DOI_ARCHI_010, reqName = Requirement.DOI_ARCHI_010_NAME)
232 private void configureServer() throws ClientMdsException {
233 LOG.traceEntry();
234 final boolean isHttpStarted = initHttpServer();
235 final boolean isHttpsStarted = initHttpsServer();
236 if (isHttpStarted || isHttpsStarted) {
237 initClients();
238 initAttachApplication();
239 } else {
240 LOG.warn("No server is configured, please check your configuration file");
241 }
242
243 LOG.traceExit();
244 }
245
246
247
248
249
250
251 private boolean initHttpServer() {
252 LOG.traceEntry();
253 final boolean isConfigured;
254 if (settings.hasValue(Consts.SERVER_HTTP_PORT)) {
255 final String httpPort = settings.getString(Consts.SERVER_HTTP_PORT);
256 final Server serverHttp = startHttpServer(Integer.parseInt(httpPort));
257 this.getServers().add(serverHttp);
258 initJettyConfiguration(serverHttp);
259 isConfigured = true;
260 } else {
261 isConfigured = false;
262 }
263 return LOG.traceExit(isConfigured);
264 }
265
266
267
268
269
270
271 private boolean initHttpsServer() {
272 LOG.traceEntry();
273 final boolean isConfigured;
274 if (settings.hasValue(Consts.SERVER_HTTPS_PORT)) {
275 final String httpsPort = settings.getString(Consts.SERVER_HTTPS_PORT);
276 final Server serverHttps = startHttpsServer(Integer.parseInt(httpsPort));
277 this.getServers().add(serverHttps);
278 initJettyConfiguration(serverHttps);
279 isConfigured = true;
280 } else {
281 isConfigured = false;
282 }
283 return LOG.traceExit(isConfigured);
284 }
285
286
287
288
289
290
291 private void initJettyConfiguration(final Server server) {
292 LOG.traceEntry(new JsonMessage(server));
293 final JettySettings jettyProps = new JettySettings(server, settings);
294 jettyProps.addParamsToServerContext();
295 LOG.traceExit();
296 }
297
298
299
300
301
302 private void initClients() {
303 LOG.traceEntry();
304 this.getClients().add(Protocol.HTTP);
305 this.getClients().add(Protocol.HTTPS);
306 this.getClients().add(Protocol.CLAP);
307 this.getClients().add(Protocol.FILE);
308 LOG.traceExit();
309 }
310
311
312
313
314 private void initAttachApplication() throws ClientMdsException {
315 LOG.traceEntry();
316 final DoiSettings doiConfig = DoiSettings.getInstance();
317 final String contextMode = doiConfig.getString(Consts.CONTEXT_MODE);
318 final ClientMDS client = new ClientMDS(ClientMDS.Context.valueOf(contextMode),
319 doiConfig.getSecret(Consts.INIST_LOGIN),
320 doiConfig.getSecret(Consts.INIST_PWD));
321 final Application appDoiProject = new DoiMdsApplication(client);
322 final Application appAdmin = new AdminApplication(client);
323 this.getDefaultHost().attach(MDS_URI, appDoiProject);
324 this.getDefaultHost().attach(CITATION_URI, new DoiCrossCiteApplication());
325 this.getDefaultHost().attachDefault(appAdmin);
326
327 RoleAuthorizer.getInstance().createRealmFor(appDoiProject);
328 RoleAuthorizer.getInstance().createRealmFor(appAdmin);
329
330 final String doiAdmin = PluginFactory.getAuthenticationSystem().getDOIAdmin();
331 addAuthenticationUserAsAdmin(doiAdmin);
332 LOG.traceExit();
333 }
334
335
336
337
338
339
340 private void addAuthenticationUserAsAdmin(final String username) {
341 LOG.traceEntry("Parameter\n username: {}", username);
342 final IAuthenticationDBHelper authenticationService = PluginFactory.
343 getAuthenticationSystem();
344 final AbstractUserRoleDBHelper manageUsers = PluginFactory.getUserManagement();
345 try {
346 boolean isFound = false;
347 final List<AuthSystemUser> authenticationUsers = authenticationService.
348 getDOIProjectMembers();
349 for (final AuthSystemUser authenticationUser : authenticationUsers) {
350 if (authenticationUser.getUsername().equals(username)) {
351 manageUsers.setUserToAdminGroup(authenticationUser.getUsername());
352 isFound = true;
353 break;
354 }
355 }
356 if (!isFound) {
357 LOG.warn("{} is not registered in the authentication system - Cannot create "
358 + "the administrator in DOI database",
359 username
360 );
361 }
362 } catch (AuthenticationAccessException ex) {
363 LOG.catching(ex);
364 LOG.warn("Cannot create an administrator: {}", ex);
365 }
366
367 LOG.traceExit();
368 }
369
370
371
372
373
374 private void startWithProxy() throws ClientMdsException {
375 LOG.traceEntry();
376 initLogServices();
377 RoleAuthorizer.getInstance();
378 ProxySettings.getInstance();
379 EmailSettings.getInstance();
380 configureServer();
381 LOG.traceExit();
382 }
383
384
385
386
387
388
389
390 private Server startHttpServer(final Integer port) {
391 LOG.traceEntry(MESSAGE_TPL, PARAMETERS, port);
392 final Server server = new Server(Protocol.HTTP, port, this);
393 return LOG.traceExit(server);
394 }
395
396
397
398
399
400
401
402 private Server startHttpsServer(final Integer port) {
403 LOG.traceEntry(MESSAGE_TPL, PARAMETERS, port);
404 final String pathKeyStore;
405 if (settings.hasValue(Consts.SERVER_HTTPS_KEYSTORE_PATH)) {
406 pathKeyStore = settings.getString(Consts.SERVER_HTTPS_KEYSTORE_PATH);
407 LOG.debug("path key store value loaded from a custom configuration file");
408 } else {
409 pathKeyStore = extractKeyStoreToPath();
410 LOG.debug("path key store value loaded from an internal configuration");
411 }
412
413 final String pathKeyTrustStore;
414 if (settings.hasValue(Consts.SERVER_HTTPS_TRUST_STORE_PATH)) {
415 pathKeyTrustStore = settings.getString(Consts.SERVER_HTTPS_TRUST_STORE_PATH);
416 } else {
417 pathKeyTrustStore = extractKeyStoreToPath();
418 }
419
420
421 final Server server = new Server(new Context(), Protocol.HTTPS, port, this);
422 final Series<Parameter> parameters = server.getContext().getParameters();
423
424 LOG.debug(MESSAGE_TPL, USE_FORWARDED_FOR_HEADER, "true", "true");
425 parameters.set(USE_FORWARDED_FOR_HEADER, "true");
426
427 LOG.debug(MESSAGE_TPL, RESTLET_MAX_TOTAL_CONNECTIONS, DoiSettings.getInstance().getString(
428 fr.cnes.doi.settings.Consts.RESTLET_MAX_TOTAL_CONNECTIONS,
429 DEFAULT_MAX_TOTAL_CONNECTIONS));
430 parameters.set(RESTLET_MAX_TOTAL_CONNECTIONS, DoiSettings.getInstance().getString(
431 fr.cnes.doi.settings.Consts.RESTLET_MAX_TOTAL_CONNECTIONS,
432 DEFAULT_MAX_TOTAL_CONNECTIONS));
433
434 LOG.debug(MESSAGE_TPL, RESTLET_MAX_CONNECTIONS_PER_HOST, DoiSettings.getInstance().
435 getString(fr.cnes.doi.settings.Consts.RESTLET_MAX_CONNECTIONS_PER_HOST,
436 DEFAULT_MAX_CONNECTIONS_PER_HOST));
437 parameters.set(RESTLET_MAX_CONNECTIONS_PER_HOST, DoiSettings.getInstance().getString(
438 fr.cnes.doi.settings.Consts.RESTLET_MAX_CONNECTIONS_PER_HOST,
439 DEFAULT_MAX_CONNECTIONS_PER_HOST));
440
441 LOG.debug(MESSAGE_TPL, SSL_CTX_FACTORY, DEFAULT_SSL_CTX);
442 parameters.add(SSL_CTX_FACTORY, DEFAULT_SSL_CTX);
443
444
445 LOG.debug(MESSAGE_TPL, KEY_STORE_PATH, pathKeyStore);
446 parameters.add(KEY_STORE_PATH, pathKeyStore);
447
448
449 LOG.debug(MESSAGE_TPL, KEY_STORE_PWD, "xxxxxxx");
450 parameters.add(KEY_STORE_PWD, settings.getSecret(Consts.SERVER_HTTPS_KEYSTORE_PASSWD));
451
452
453 LOG.debug(MESSAGE_TPL, KEY_STORE_TYPE, KeyStore.getDefaultType());
454 parameters.add(KEY_STORE_TYPE, KeyStore.getDefaultType());
455
456
457 LOG.debug(MESSAGE_TPL, KEY_PWD, "xxxxxxxx");
458 parameters.add(KEY_PWD, settings.getSecret(Consts.SERVER_HTTPS_SECRET_KEY));
459
460
461 LOG.debug(MESSAGE_TPL, TRUST_STORE_PATH, pathKeyTrustStore);
462 parameters.add(TRUST_STORE_PATH, pathKeyTrustStore);
463
464
465 LOG.debug(MESSAGE_TPL, TRUST_STORE_PWD, "xxxxx");
466 parameters.add(TRUST_STORE_PWD, settings.getSecret(Consts.SERVER_HTTPS_TRUST_STORE_PASSWD));
467
468
469 LOG.debug(MESSAGE_TPL, TRUST_STORE_TYPE, KeyStore.getDefaultType());
470 parameters.add(TRUST_STORE_TYPE, KeyStore.getDefaultType());
471
472 return LOG.traceExit(server);
473 }
474
475
476
477
478
479
480 private String extractKeyStoreToPath() {
481 LOG.traceEntry();
482 String result;
483 final Representation jks = new ClientResource(
484 LocalReference.createClapReference("class/" + JKS_FILE)
485 ).get();
486 try {
487 final Path outputDirectory = new File(JKS_DIRECTORY).toPath();
488 if (Files.notExists(outputDirectory)) {
489 Files.createDirectory(outputDirectory);
490 LOG.info("Creates {} directory to extract {} in it", outputDirectory, JKS_FILE);
491 }
492 final String outputJksLocation = outputDirectory.getFileName()
493 + File.separator
494 + JKS_FILE;
495
496 final File outputFile = new File(outputJksLocation);
497 Files.copy(jks.getStream(),
498 outputFile.toPath(),
499 java.nio.file.StandardCopyOption.REPLACE_EXISTING
500 );
501 LOG.info("Copy/replace if exists {} in {}", JKS_FILE, outputDirectory, JKS_FILE);
502 result = outputJksLocation;
503 } catch (IOException ex) {
504 LOG.fatal("Unable to extract keystore from class/" + JKS_FILE, ex);
505 result = "";
506 }
507 return LOG.traceExit(result);
508 }
509
510
511
512
513 @Override
514 public synchronized void start() throws Exception {
515 LOG.info("Starting server ...");
516 addPath(DoiSettings.getInstance().getPathApp() + File.separatorChar + "plugins");
517 super.start();
518 LOG.info("Server started");
519 }
520
521
522
523
524 @Override
525 public synchronized void stop() throws Exception {
526 LOG.info("Stopping the server ...");
527 super.stop();
528 LOG.info("Stopping Authentication plugin");
529 PluginFactory.getAuthenticationSystem().release();
530 LOG.info("Stopping Project plugin");
531 PluginFactory.getProjectSuffix().release();
532 LOG.info("Stopping Token plugin");
533 PluginFactory.getToken().release();
534 LOG.info("Stopping UserManagement plugin");
535 PluginFactory.getUserManagement().release();
536 EmailSettings.getInstance().sendMessage("[DOI] Stopping Server",
537 "The server has been interrupted");
538 LOG.info("Server stopped");
539 }
540
541 }