View Javadoc

1   /*
2    * Copyright (C) 2017-2019 Centre National d'Etudes Spatiales (CNES).
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 3.0 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17   * MA 02110-1301  USA
18   */
19  package fr.cnes.doi.application;
20  
21  import fr.cnes.doi.client.ClientMDS;
22  import fr.cnes.doi.exception.ClientMdsException;
23  import fr.cnes.doi.services.DOIUsersUpdate;
24  import java.util.Arrays;
25  import java.util.concurrent.TimeUnit;
26  
27  import org.apache.logging.log4j.LogManager;
28  import org.apache.logging.log4j.Logger;
29  import org.restlet.Request;
30  import org.restlet.Response;
31  import org.restlet.Restlet;
32  import org.restlet.data.LocalReference;
33  import org.restlet.data.Method;
34  import org.restlet.data.Reference;
35  import org.restlet.data.MediaType;
36  import org.restlet.data.Status;
37  import org.restlet.resource.Directory;
38  import org.restlet.routing.Filter;
39  import org.restlet.routing.Redirector;
40  import org.restlet.routing.Router;
41  import org.restlet.security.ChallengeAuthenticator;
42  import org.restlet.security.Role;
43  import org.restlet.security.RoleAuthorizer;
44  import org.restlet.service.TaskService;
45  
46  import fr.cnes.doi.logging.business.JsonMessage;
47  import fr.cnes.doi.resource.admin.AuthenticateResource;
48  import fr.cnes.doi.resource.admin.ConfigIhmResource;
49  import fr.cnes.doi.resource.admin.FooterIhmResource;
50  import fr.cnes.doi.resource.admin.ManageProjectsResource;
51  import fr.cnes.doi.resource.admin.ManageSuperUserResource;
52  import fr.cnes.doi.resource.admin.ManageSuperUsersResource;
53  import fr.cnes.doi.resource.admin.ManageUsersResource;
54  import fr.cnes.doi.resource.admin.RedirectingResource;
55  import fr.cnes.doi.resource.admin.SuffixProjectsDoisResource;
56  import fr.cnes.doi.resource.admin.SuffixProjectsResource;
57  import fr.cnes.doi.resource.admin.TokenResource;
58  import fr.cnes.doi.security.AllowerIP;
59  import fr.cnes.doi.services.LandingPageMonitoring;
60  import fr.cnes.doi.services.UpdateTokenDataBase;
61  import fr.cnes.doi.settings.Consts;
62  import fr.cnes.doi.settings.DoiSettings;
63  import fr.cnes.doi.utils.spec.CoverageAnnotation;
64  import fr.cnes.doi.utils.spec.Requirement;
65  import java.util.List;
66  import org.apache.logging.log4j.ThreadContext;
67  import org.restlet.data.ClientInfo;
68  import org.restlet.routing.Template;
69  
70  /**
71   * Provides an application for handling features related to the administration
72   * system of the DOI server.
73   *
74   * The administration application provides the following features:
75   * <ul>
76   * <li>An asynchronous task to check the availability of created landing pages
77   * each {@value #PERIOD_SCHEDULER} days</li>
78   * <li>The form for creating DOI</li>
79   * <li>The Datacite status page to check Datacite services availability</li>
80   * <li>The Datacite stats page</li>
81   * <li>A service to create random string as a part of the DOI suffix</li>
82   * <li>A token service for creating token and to get token information</li>
83   * </ul>
84   * <p>
85   * <b>Security</b><br>
86   * --------------<br>
87   * The authentication is done by a simple login/password. Only users having the
88   * group "admin" will be allowed to log in to this application.<br>
89   * The website for creating DOI is opened on the net whereas the others services
90   * are filtered by IP. The allowed IPs are localhost and the IPs defined in
91   * {@value fr.cnes.doi.settings.Consts#ADMIN_IP_ALLOWER} attribute from the
92   * configuration file
93   *
94   * <p>
95   * <b>Routing</b><br>
96   * --------------<br>
97   * <br>
98   * root (DOI creation web form - no authorization)<br>
99   * |<br>
100  * |__ resources (status page - no authorization)<br>
101  * |__ status (Datacite status page - authorization)<br>
102  * |__ stats (Datacite stats page - authorization)<br>
103  * |_ ____________<br>
104  * |_|************|____ suffixProject (Get a random suffix - authorization)<br>
105  * |_|IP_filtering|____ token (Create a token - authorization)<br>
106  * |_|____________|____ token/{tokenID} (Get token information -
107  * authorization)<br>
108  *
109  * @see <a href="http://status.datacite.org">Datacite status page</a>
110  * @see <a href="https://stats.datacite.org/#tab-prefixes">Datacite stats
111  * page</a>
112  * @see SuffixProjectsResource Creating a project suffix for DOI
113  * @see TokenResource Creating a token and getting information about a token
114  * @author Jean-Christophe Malapert (jean-christophe.malapert@cnes.fr)
115  */
116 @Requirement(reqId = Requirement.DOI_SRV_130, reqName = Requirement.DOI_SRV_130_NAME)
117 @Requirement(reqId = Requirement.DOI_SRV_140, reqName = Requirement.DOI_SRV_140_NAME)
118 @Requirement(reqId = Requirement.DOI_SRV_150, reqName = Requirement.DOI_SRV_150_NAME)
119 @Requirement(reqId = Requirement.DOI_SRV_180, reqName = Requirement.DOI_SRV_180_NAME)
120 //TODO SRV 190
121 @Requirement(reqId = Requirement.DOI_SRV_190, reqName = Requirement.DOI_SRV_190_NAME,
122         coverage = CoverageAnnotation.NONE)
123 @Requirement(reqId = Requirement.DOI_DISPO_020, reqName = Requirement.DOI_DISPO_020_NAME)
124 public final class AdminApplication extends AbstractApplication {
125 
126     /**
127      * Application name.
128      */
129     public static final String NAME = "Admin Application";
130 
131     /**
132      * URI {@value #ADMIN_URI} to access to the resources of the system
133      * administration.
134      */
135     public static final String ADMIN_URI = "/admin";
136 
137     /**
138      * URI {@value #RESOURCE_URI} to access to the resources of the status page.
139      */
140     public static final String RESOURCE_URI = "/resources";
141 
142     /**
143      * URI {@value #STATUS_URI} to access to the status page.
144      */
145     public static final String STATUS_URI = "/status";
146 
147     /**
148      * URI {@value #STATS_URI} to access to Stats page.
149      */
150     public static final String STATS_URI = "/stats";
151 
152     /**
153      * URI {@value #ROLE_USERS_URI} to check access rights.
154      */
155     public static final String ROLE_USERS_URI = "/roles/users";
156 
157     /**
158      * URI {@value #ROLE_ADMIN_URI} to check admin access rights.
159      */
160     public static final String ROLE_ADMIN_URI = "/roles/admin";
161 
162     /**
163      * URI {@value #SUFFIX_PROJECT_URI} to create a project suffix.
164      */
165     public static final String SUFFIX_PROJECT_URI = "/projects";
166 
167     /**
168      * Project suffix template.
169      */
170     public static final String SUFFIX_PROJECT_NAME_TEMPLATE = "suffixProject";
171 
172     /**
173      * URI {@value #SUFFIX_PROJECT_NAME} to manage a project suffix.
174      */
175     public static final String SUFFIX_PROJECT_NAME = "/{" + SUFFIX_PROJECT_NAME_TEMPLATE + "}";
176 
177     /**
178      * URI {@value #DOIS_URI} to get dois from a specific project.
179      */
180     public static final String DOIS_URI = "/dois";
181 
182     /**
183      * URI {@value #USERS_URI} to handle users.
184      */
185     public static final String USERS_URI = "/users";
186 
187     /**
188      * URI {@value #SUPERUSERS_URI} to handle superusers.
189      */
190     public static final String SUPERUSERS_URI = "/superusers";
191 
192     /**
193      * Template user.
194      */
195     public static final String USERS_NAME_TEMPLATE = "userName";
196 
197     /**
198      * URI {@value #USERS_NAME} to handle user.
199      */
200     public static final String USERS_NAME = "/{" + USERS_NAME_TEMPLATE + "}";
201 
202     /**
203      * URI {@value #TOKEN_URI} to create a token.
204      */
205     public static final String TOKEN_URI = "/token";
206 
207     /**
208      * Token template.
209      */
210     public static final String TOKEN_TEMPLATE = "tokenID";
211 
212     /**
213      * URI {@value #TOKEN_NAME_URI} to handle to get information from a token.
214      */
215     public static final String TOKEN_NAME_URI = "/{" + TOKEN_TEMPLATE + "}";
216 
217     /**
218      * URI {@value #IHM_URI} where the web site is located.
219      */
220     public static final String IHM_URI = "/ihm";
221     
222     /**
223      * Logger.
224      */
225     private static final Logger LOG = LogManager.getLogger(AdminApplication.class.getName());
226 
227     /**
228      * URI {@value #IHM_CONFIG_URI} where the configuration file is located.
229      */
230     private static final String IHM_CONFIG_URI = "/js/config.js";
231 
232     /**
233      * URI {@value #IHM_FOOTER_URI} where the footer file is located.
234      */
235     private static final String IHM_FOOTER_URI = "/footer.txt";
236 
237     /**
238      * Location of the resources for the status page in the classpath.
239      */
240     private static final String STATUS_PAGE_CLASSPATH = "class/website";
241 
242     /**
243      * Location of the resources for the IHM in the classpath.
244      */
245     private static final String IHM_CLASSPATH = "class/ihm";
246 
247     /**
248      * Location of the resources for the API docs in the classpath.
249      */
250     private static final String API_CLASSPATH = "class/docs";
251 
252     /**
253      * The period between successive executions : {@value #PERIOD_SCHEDULER}.
254      */
255     private static final int PERIOD_SCHEDULER = 1;
256 
257     /**
258      * The period between successive executions :
259      * {@value #PERIOD_SCHEDULER_FOR_TOKEN_DB}.
260      */
261     private static final int PERIOD_SCHEDULER_FOR_TOKEN_DB = 1;
262 
263     /**
264      * The time unit of the initialDelay and period parameters.
265      */
266     private static final TimeUnit PERIOD_UNIT = TimeUnit.DAYS;
267 
268     /**
269      * DataCite Status page {@value #TARGET_URL}.
270      */
271     private static final String TARGET_URL = "http://status.datacite.org";
272 
273     /**
274      * DataCite Stats page {@value #TARGET_STATS_URL}.
275      */
276     private static final String TARGET_STATS_URL = "https://stats.datacite.org/#tab-prefixes";
277     
278     /**
279      * ClientMDS
280      */
281     private final ClientMDS client;
282 
283     /**
284      * Constructor.
285      * @param client Client MDS
286      */
287     public AdminApplication(final ClientMDS client) {
288         super();
289         this.client = client;
290         init();
291     }
292 
293     /**
294      * Defines services and metadata.
295      */
296     private void init() {
297         setName(NAME);
298         setDescription("Provides an application for handling features related to "
299                 + "the administration system of the DOI server.");        
300         this.setTaskService(createTaskService());
301         this.setTaskService(createUpdateDataBaseTaskService());
302         this.setTaskService(periodicalyDeleteExpiredTokenFromDB());
303         getMetadataService().addExtension("xsd", MediaType.TEXT_XML, true);
304     }
305 
306     /**
307      * A task checking status of landing pages each 30 days.
308      *
309      * @return A task
310      */
311     @Requirement(reqId = Requirement.DOI_DISPO_020, reqName = Requirement.DOI_DISPO_020_NAME)
312     private TaskService createTaskService() {
313         LOG.traceEntry();
314         final TaskService checkLandingPageTask = new TaskService(true);
315         LOG.info("Sets CheckLandingPage running at each {} {}", PERIOD_SCHEDULER, PERIOD_UNIT);
316         checkLandingPageTask.scheduleAtFixedRate(
317                 new LandingPageMonitoring(this.client), 0,
318                 PERIOD_SCHEDULER, PERIOD_UNIT
319         );
320         return LOG.traceExit(checkLandingPageTask);
321     }
322 
323     /**
324      * A task removing expired tokens in data base each days.
325      *
326      * @return A task
327      */
328     private TaskService periodicalyDeleteExpiredTokenFromDB() {
329         LOG.traceEntry();
330         final TaskService checkExpiredTokenTask = new TaskService(true);
331         LOG.info("Sets checkExpiredTokenTask running at each {} {}", PERIOD_SCHEDULER_FOR_TOKEN_DB,
332                 PERIOD_UNIT);
333         checkExpiredTokenTask.scheduleAtFixedRate(
334                 new UpdateTokenDataBase(), 0,
335                 PERIOD_SCHEDULER_FOR_TOKEN_DB, PERIOD_UNIT
336         );
337         return LOG.traceExit(checkExpiredTokenTask);
338     }
339 
340     /**
341      * A task updating DOI users database from authentication service at each
342      * configurable period of time.
343      *
344      * @return A task
345      */
346     private TaskService createUpdateDataBaseTaskService() {
347         LOG.traceEntry();
348         final TaskService updateDataBaseTask = new TaskService(true);
349         LOG.info("Sets UpdateDataBaseTask running at each {} {}", PERIOD_SCHEDULER, PERIOD_UNIT);
350         try {
351             updateDataBaseTask.scheduleAtFixedRate(
352                     new DOIUsersUpdate(), 0,
353                     DoiSettings.getInstance().getInt(Consts.DB_UPDATE_JOB_PERIOD), TimeUnit.MINUTES
354             );
355         } catch(NoClassDefFoundError e) {
356             LOG.error(e);
357         }
358         return LOG.traceExit(updateDataBaseTask);
359     }
360 
361     /**
362      * Creates a router for the AdminApplication. This router routes :
363      * <ul>
364      * <li>the web resources for the website with no authentication</li>
365      * <li>the REST resources for the system administration with
366      * authentication/authorization</li>
367      * </ul>
368      * The web resources are attached by default to the AdminApplication where
369      * as the REST resources for the system administration are attached with the
370      * {@link AdminApplication#ADMIN_URI}
371      *
372      * @see AdminApplication#createWebSiteRouter() the router that contains the
373      * the web resources
374      * @see AdminApplication#createAdminRouter() the router that contains the
375      * REST resources
376      * @see AdminApplication#createAuthenticator() the authentication mechanism
377      * @see AdminApplication#createRoleAuthorizer() the authorization mechanism
378      * @return Router
379      */
380     @Override
381     public Restlet createInboundRoot() {
382         LOG.traceEntry();
383         
384         final Filter logContext = new Filter() {
385             /**
386              * Get the IP client from proxy (if there is one) and set it in
387              * the header.
388              * 
389              * @param request request
390              * @param response response
391              * @return 0
392              */
393             @Override
394             protected int beforeHandle(final Request request, final Response response) {
395                 final ClientInfo clientInfo = request.getClientInfo();
396                 final String ipAddress = request.getHeaders().getFirstValue(
397                         Consts.PROXIFIED_IP, clientInfo.getUpstreamAddress()
398                 );
399                 ThreadContext.put(Consts.LOG_IP_ADDRESS, ipAddress);
400                 return Filter.CONTINUE;
401             }
402         }; 
403         
404         // Defines the strategy of authentication (authentication is not required)
405         //   - authentication with login/pwd
406         final ChallengeAuthenticator challAuth = createAuthenticatorLoginBased();
407         challAuth.setOptional(true);
408 
409         //   - authentication with token
410         final ChallengeAuthenticator challTokenAuth = createTokenAuthenticator();
411         challTokenAuth.setOptional(false);
412         //if already authenticate 
413         challTokenAuth.setMultiAuthenticating(false);
414 
415         // Defines the authorization
416         final RoleAuthorizer authorizer = createRoleAuthorizer();
417 
418         // Defines the admin router as private
419         final String ips = DoiSettings.getInstance().getString(Consts.ADMIN_IP_ALLOWER);
420         final boolean isEnabled = ips != null;
421         final AllowerIP blocker = new AllowerIP(getContext(), isEnabled);
422 
423         // Defines the routers
424         final Router webSiteRouter = createWebSiteRouter();
425         final Router adminRouter = createAdminRouter();
426         
427         // pipeline of authentication and authorization
428         challAuth.setNext(challTokenAuth);
429         challTokenAuth.setNext(authorizer);
430         authorizer.setNext(blocker);
431         blocker.setNext(adminRouter);
432 
433         final Router router = new Router(getContext());
434         router.attachDefault(webSiteRouter);
435 
436         router.attach(ADMIN_URI, challAuth);
437         
438         logContext.setNext(router);        
439 
440         return LOG.traceExit(logContext);
441     }
442 
443     /**
444      * Creates a authorization based on the role. Only users attached to the
445      * role {@link fr.cnes.doi.security.RoleAuthorizer#ROLE_ADMIN} are allowed
446      *
447      * @return the authorization that contains the access rights to the
448      * resources.
449      */
450     private RoleAuthorizer createRoleAuthorizer() {
451         LOG.traceEntry();
452 
453         final RoleAuthorizer roleAuth = new RoleAuthorizer() {
454 
455             /**
456              * Cancel verification on pre-flight OPTIONS method
457              *
458              * @param request request
459              * @param response response
460              * @return the result
461              */
462             @Override
463             public int beforeHandle(final Request request, final Response response) {
464                 final Method requestMethod = request.getMethod();
465                 final Reference requestReference = request.getOriginalRef();
466                 final String lastSeg = requestReference.getLastSegment();
467                 final String path = requestReference.getPath();
468                 boolean ignoreVerification = false;
469 
470                 if (requestMethod.equals(Method.OPTIONS)) {
471                     // options method is allowed independently of the role
472                     // just need to be authenticated
473                     ignoreVerification = true;
474                 } else if (!requestMethod.equals(Method.DELETE) && !requestMethod.equals(Method.GET)
475                         && requestReference.toString().contains(ADMIN_URI + TOKEN_URI)) {
476                     // token resource is allowed independently of the role
477                     // just need to be authenticated because we want to access to the 
478                     //authentication page of the GUI without authentication
479                     ignoreVerification = true;
480                 } else if (requestMethod.equals(Method.GET)) {
481                     // no check of the role when getting the list of projects, superusers and dois 
482                     if ("projects".equals(lastSeg) && requestReference.hasQuery()) {
483                         ignoreVerification = true;
484                     }
485                     // ignore method GET dois from project
486                     if ("dois".equals(lastSeg)) {
487                         ignoreVerification = true;
488                     }
489                     // Checks authentication for "users" group
490                     if (path.contains(ADMIN_URI + ROLE_USERS_URI)) {
491                         ignoreVerification = true;
492                     }
493                 }
494 
495                 final int status;
496                 if (ignoreVerification) {
497                     response.setStatus(Status.SUCCESS_OK);
498                     status = CONTINUE;
499                 } else {
500                     status = super.beforeHandle(request, response);
501                 }
502                 return status;
503             }
504 
505         };
506         roleAuth.setAuthorizedRoles(
507                 Arrays.asList(
508                         Role.get(this, fr.cnes.doi.security.RoleAuthorizer.ROLE_ADMIN)
509                 )
510         );
511 
512         return LOG.traceExit(roleAuth);
513     }
514 
515     /**
516      * Creates a router for REST services for the system administration. This
517      * router contains the following resources :
518      * <ul>
519      * <li>{@link AdminApplication#SUFFIX_PROJECT_URI} resource to handle the
520      * project suffix, which is used in the Digital Object Identifier</li>
521      * <li>{@link AdminApplication#TOKEN_URI} resource to handle the token for
522      * the authentication</li>
523      * </ul>
524      *
525      * @see SuffixProjectsResource Resource to handle the the project suffix
526      * @see TokenResource Resource to handle the token resource
527      * @return the router
528      */
529     private Router createAdminRouter() {
530         LOG.traceEntry();
531 
532         final Router router = new Router(getContext());
533 
534         router.attach(SUFFIX_PROJECT_URI, SuffixProjectsResource.class);
535 
536         router.attach(SUFFIX_PROJECT_URI + SUFFIX_PROJECT_NAME, ManageProjectsResource.class);
537         router.attach(SUFFIX_PROJECT_URI + SUFFIX_PROJECT_NAME + DOIS_URI,
538                 SuffixProjectsDoisResource.class);
539 
540         router.attach(SUFFIX_PROJECT_URI + SUFFIX_PROJECT_NAME + USERS_URI,
541                 ManageUsersResource.class);
542         router.attach(SUFFIX_PROJECT_URI + SUFFIX_PROJECT_NAME + USERS_URI + USERS_NAME,
543                 ManageUsersResource.class);
544 
545         router.attach(SUPERUSERS_URI, ManageSuperUsersResource.class);
546         router.attach(SUPERUSERS_URI + USERS_NAME, ManageSuperUserResource.class);
547 
548         router.attach(TOKEN_URI, TokenResource.class);
549         router.attach(TOKEN_URI + TOKEN_NAME_URI, TokenResource.class);
550 
551         router.attach(ROLE_USERS_URI, AuthenticateResource.class);
552         router.attach(ROLE_ADMIN_URI, AuthenticateResource.class);
553 
554         return LOG.traceExit(router);
555     }
556 
557     /**
558      * Creates a router for the web site resources. This router contains the
559      * following resources:
560      * <ul>
561      * <li>{@link AdminApplication#RESOURCE_URI} to distribute the web resources
562      * for the status page</li>
563      * <li>the website resources attached by default when it is available</li>
564      * </ul>
565      * The website is located to {@link AdminApplication#IHM_URI} directory when
566      * it is distributed by the DOI server.
567      *
568      * @return The router for the public web site
569      */
570     private Router createWebSiteRouter() {
571         LOG.traceEntry();
572 
573         final Router router = new Router(getContext());
574         addStatusPage(router);
575         addServicesStatus(router);
576         addServicesStats(router);
577         addRouteForWebSite(router);
578 
579         return LOG.traceExit(router);
580     }
581 
582     /**
583      * Adds route {@value #RESOURCE_URI} to the status page.
584      *
585      * The resources of the status page are located in the classpath
586      * {@value #STATUS_PAGE_CLASSPATH}.
587      *
588      * @param router router
589      */
590     private void addStatusPage(final Router router) {
591         LOG.traceEntry("Parameter\n router: {}", new JsonMessage(router));
592 
593         final Directory directory = new Directory(
594                 getContext(),
595                 LocalReference.createClapReference(STATUS_PAGE_CLASSPATH)
596         );
597         directory.setDeeplyAccessible(true);
598         router.attach(RESOURCE_URI, directory);
599 
600         LOG.traceExit();
601     }
602 
603     /**
604      * Adds route attacURI to the target according to redirection mode.
605      *
606      * @param router router
607      * @param redirectorMode redirection mode
608      * @param target target
609      * @param attachURI attachURI
610      */
611     private void addServices(final Router router, final int redirectorMode, final String target,
612             final String attachURI) {
613         LOG.traceEntry("Parameters\n   router: {}\n   redirectorMode: {}\n   "
614                 + "target: {}\n  attachURI: {}",
615                 new JsonMessage(router), redirectorMode, target, attachURI);
616 
617         final Redirector redirector = new Redirector(getContext(), target, redirectorMode);
618 
619         final Filter authentication = new Filter() {
620             /**
621              * {@inheritDoc }
622              */
623             @Override
624             protected int doHandle(final Request request, final Response response) {
625                 response.setLocationRef(target);
626                 response.setStatus(Status.REDIRECTION_PERMANENT);
627                 return super.doHandle(request, response);
628             }
629         };
630         authentication.setNext(redirector);
631         router.attach(attachURI, authentication);
632         LOG.traceExit();
633     }
634 
635     /**
636      * Adds route {@value #STATUS_URI} to the services describing the DataCite
637      * status.
638      *
639      * @param router router
640      */
641     private void addServicesStatus(final Router router) {
642         this.addServices(router, Redirector.MODE_SERVER_OUTBOUND, TARGET_URL, STATUS_URI);
643     }
644 
645     /**
646      * Adds route {@value #STATS_URI} to the services giving the DataCite stats.
647      *
648      * @param router router
649      */
650     private void addServicesStats(final Router router) {
651         this.addServices(router, Redirector.MODE_CLIENT_PERMANENT, TARGET_STATS_URL, STATS_URI);
652     }
653 
654     /**
655      * Adds default route to the website when it exists. The website must be
656      * located in the {@value #IHM_URI} directory.
657      *
658      * @param router router
659      */
660     private void addRouteForWebSite(final Router router) {
661         LOG.traceEntry("Parameter : {}", new JsonMessage(router));
662 
663         final Directory ihm = new Directory(
664                 getContext(),
665                 LocalReference.createClapReference(IHM_CLASSPATH)
666         );
667         ihm.setListingAllowed(false);
668         ihm.setDeeplyAccessible(true);
669         ihm.setIndexName("authentication");
670 
671         router.attach(IHM_URI, RedirectingResource.class, Template.MODE_EQUALS);
672         router.attach(IHM_URI + "/", RedirectingResource.class, Template.MODE_EQUALS);
673         router.attach(IHM_URI + IHM_FOOTER_URI, FooterIhmResource.class);
674         router.attach(IHM_URI + IHM_CONFIG_URI, ConfigIhmResource.class);
675         router.attach(IHM_URI, ihm);
676 
677         LOG.traceExit();
678     }
679 
680     /**
681      * Returns the logger.
682      *
683      * @return the logger
684      */
685     @Override
686     public Logger getLog() {
687         return LOG;
688     }
689 
690 
691     /**
692      * Returns only the dois within the specified project from the search
693      * result.
694      *
695      * @param idProject project ID
696      * @return the search result
697      * @throws fr.cnes.doi.exception.ClientMdsException it happens when a problem
698      * happens with Datacite
699      */
700     public List<String> getDois(final String idProject) throws ClientMdsException {
701         return this.client.getDois(idProject);
702     }    
703 }