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.logging.security;
20  
21  import fr.cnes.doi.settings.Consts;
22  import fr.cnes.doi.utils.Utils;
23  import fr.cnes.doi.utils.spec.Requirement;
24  import java.nio.charset.Charset;
25  import java.util.ArrayList;
26  import java.util.Base64;
27  import java.util.Collection;
28  import java.util.List;
29  import org.apache.logging.log4j.LogManager;
30  import org.apache.logging.log4j.ThreadContext;
31  import org.restlet.Request;
32  import org.restlet.Response;
33  import org.restlet.data.ClientInfo;
34  import org.restlet.data.Status;
35  import org.restlet.routing.Filter;
36  import org.restlet.security.Role;
37  import org.restlet.security.User;
38  
39  /**
40   * Log filter for DOI security
41   *
42   * @author Jean-Christophe Malapert (jean-christophe.malapert@cnes.fr)
43   */
44  @Requirement(reqId = Requirement.DOI_ARCHI_020, reqName = Requirement.DOI_ARCHI_020_NAME)
45  public class DoiSecurityLogFilter extends Filter {
46  
47      /**
48       * Instantiates a new sitools log filter.
49       *
50       */
51      public DoiSecurityLogFilter() {
52          super();
53      }
54  
55      /**
56       * Allows filtering after processing by the next Restlet. Does nothing by
57       * default.
58       *
59       * @param request request
60       * @param response response
61       * @see org.restlet.routing.Filter#afterHandle(org.restlet.Request,
62       * org.restlet.Response)
63       */
64      @Override
65      protected void afterHandle(final Request request,
66              final Response response) {
67          super.afterHandle(request, response);
68  
69          final String targetUri = request.getResourceRef().getIdentifier();
70          final String method = request.getMethod().getName();
71          final ClientInfo clientInfo = request.getClientInfo();
72          final String upStreamIp = ThreadContext.get(Consts.LOG_IP_ADDRESS);
73          if (request.getClientInfo().isAuthenticated()) {
74              final String authenticationMethod = request.getChallengeResponse().getScheme().
75                      getTechnicalName();
76              final String identifier = request.getClientInfo().getUser().getIdentifier();
77              final String profiles = computeProfiles(clientInfo);
78              LogManager.getLogger(Utils.SECURITY_LOGGER_NAME).info(
79                      "User: {} \tProfile(s): {}\t - [{}] - [{}] {} {} {} - {}",
80                      identifier, profiles, upStreamIp, authenticationMethod,
81                      method, targetUri, response.getStatus().getCode(),
82                      clientInfo.getAgent());
83          } else if (response.getStatus().equals(Status.CLIENT_ERROR_UNAUTHORIZED)) {
84              final String authenticationMethod = request.getChallengeResponse().getScheme().
85                      getTechnicalName();
86              final String identifier;
87              final User user = request.getClientInfo().getUser();
88              if (user == null) {
89                  final String auth = request.getChallengeResponse().getRawValue();
90                  final String decodedAuth = new String(
91                          Base64.getDecoder().decode(auth), Charset.defaultCharset()
92                  );
93                  final String[] userLogin = decodedAuth.split(":");                
94                  identifier = userLogin[0];                
95              } else {
96                  identifier = user.getIdentifier();                
97              }            
98              LogManager.getLogger(Utils.SECURITY_LOGGER_NAME).info(
99                      "Authentication failed for user: {} \t - [{}] - [{}] {} {} - {}",
100                     identifier, upStreamIp, authenticationMethod,
101                     method, targetUri, clientInfo.getAgent());
102         }
103     }
104 
105     /**
106      * Represents the list of roles as a single string.
107      *
108      * @param clientInfo Client information
109      * @return the roles
110      */
111     private String computeProfiles(final ClientInfo clientInfo) {
112         final List<Role> roles = clientInfo.getRoles();
113         final Collection<String> rolesStr = new ArrayList<>();
114         for (final Role role : roles) {
115             rolesStr.add(role.getName());
116         }
117         return String.join(",", rolesStr);
118     }
119 }