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.security;
20  
21  import fr.cnes.doi.db.AbstractTokenDBHelper;
22  import fr.cnes.doi.db.AbstractUserRoleDBHelper;
23  import fr.cnes.doi.logging.business.JsonMessage;
24  import fr.cnes.doi.plugin.PluginFactory;
25  import fr.cnes.doi.utils.spec.Requirement;
26  import io.jsonwebtoken.Claims;
27  import io.jsonwebtoken.Jws;
28  import org.apache.logging.log4j.LogManager;
29  import org.apache.logging.log4j.Logger;
30  import org.restlet.Request;
31  import org.restlet.Response;
32  import org.restlet.data.ChallengeResponse;
33  import org.restlet.data.ChallengeScheme;
34  import org.restlet.security.Verifier;
35  
36  /**
37   * Security class for checking token.
38   *
39   * @author Jean-Christophe Malapert (jean-christophe.malapert@cnes.fr)
40   */
41  @Requirement(reqId = Requirement.DOI_AUTH_020, reqName = Requirement.DOI_AUTH_020_NAME)
42  public class TokenBasedVerifier implements Verifier {
43  
44      /**
45       * Logger.
46       */
47      private static final Logger LOG = LogManager.getLogger(TokenBasedVerifier.class.getName());
48  
49      /**
50       * Token DB.
51       */
52      private final AbstractTokenDBHelper tokenDB;
53  
54      /**
55       * Constructor.
56       *
57       * @param tokenDB token DB
58       */
59      public TokenBasedVerifier(final AbstractTokenDBHelper tokenDB) {
60          LOG.traceEntry(new JsonMessage(tokenDB));
61          this.tokenDB = tokenDB;
62      }
63  
64      /**
65       * Verifies the token.
66       *
67       * @param request request
68       * @param response response
69       * @return the result
70       */
71      @Override
72      public int verify(final Request request, final Response response) {
73          LOG.traceEntry(new JsonMessage(request));
74          final int result;
75          final ChallengeResponse challResponse = request.getChallengeResponse();
76  
77          if (challResponse == null) {
78              result = Verifier.RESULT_MISSING;
79          } else if (challResponse.getScheme().equals(ChallengeScheme.HTTP_BASIC)) {
80              result = Verifier.RESULT_MISSING;
81          } else {
82              result = processAuthentication(request, challResponse);
83          }
84          return LOG.traceExit(result);
85      }
86  
87      /**
88       * Process Authentication.
89       *
90       * @param request request
91       * @param challResponse authentication object
92       * @return the authentication status
93       */
94      private int processAuthentication(final Request request,
95              final ChallengeResponse challResponse) {
96          LOG.traceEntry(new JsonMessage(request));
97          final int result;
98          final String token = challResponse.getRawValue();
99          LOG.debug("Token from challenge response : {}", token);
100         if (token == null) {
101             LOG.warn("Token is missing !");
102             result = Verifier.RESULT_MISSING;
103         } else if (TokenSecurity.getInstance().isExpired(token)) {
104             LOG.debug("Token is expired !");
105             result = Verifier.RESULT_STALE;
106         } else if (this.tokenDB.isExist(token)) {
107             LOG.debug("Token exists in the database.");
108             result = processToken(request, token);
109         } else {
110             LOG.error("Token is invalid !");
111             result = Verifier.RESULT_INVALID;
112         }
113         return LOG.traceExit(result);
114     }
115 
116     /**
117      * Process token.
118      *
119      * @param request request
120      * @param token token
121      * @return the status given by {@link Verifier}
122      */
123     private int processToken(final Request request, final String token) {
124         LOG.traceEntry(new JsonMessage(request));
125         LOG.traceEntry(token);
126         final AbstractUserRoleDBHelper manageUsers = PluginFactory.getUserManagement();
127         final int result = Verifier.RESULT_VALID;
128         final Jws<Claims> tokenInfo = TokenSecurity.getInstance().getTokenInformation(token);
129         final Claims body = tokenInfo.getBody();
130         final String userID = body.getSubject();
131         final Integer projectID = (Integer) body.get(TokenSecurity.PROJECT_ID);
132         LOG.info("token {} is valid, {} for {} are authenticated", token, userID, projectID);
133         request.getClientInfo().setUser(manageUsers.getRealm().findUser(userID));
134 
135         return LOG.traceExit(result);
136     }
137 }