From d890b3b5263ce02adac0b5ef6dbcf1b33b87835e Mon Sep 17 00:00:00 2001 From: BEAUVAIS ANTOINE <antoine.beauvais@etu.unistra.fr> Date: Fri, 24 Sep 2021 01:03:45 +0200 Subject: [PATCH] Added authentication system through API key. --- .gitignore | 4 +- .../java/fr/unistra/sil/erp/back/Config.java | 46 -------- .../fr/unistra/sil/erp/back/WebMvcConfig.java | 88 +++++++++++++++ .../api/ApiRetrieveCategoriesController.java | 2 +- .../api/ApiRetrieveInfoController.java | 2 +- .../controller/api/ApiRetrieveStocks.java | 2 +- .../api/ApiSubmitTransactionController.java | 2 +- .../api/ApiAuthenticationInterceptor.java | 101 ++++++++++++++++++ 8 files changed, 196 insertions(+), 51 deletions(-) delete mode 100644 src/main/java/fr/unistra/sil/erp/back/Config.java create mode 100644 src/main/java/fr/unistra/sil/erp/back/WebMvcConfig.java create mode 100644 src/main/java/fr/unistra/sil/erp/back/interceptor/api/ApiAuthenticationInterceptor.java diff --git a/.gitignore b/.gitignore index 6ff2c46..9639095 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/**/build/ !**/src/test/**/build/ +src/main/resources/apikey.properties ### STS ### .apt_generated @@ -45,7 +46,8 @@ dev.db .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* diff --git a/src/main/java/fr/unistra/sil/erp/back/Config.java b/src/main/java/fr/unistra/sil/erp/back/Config.java deleted file mode 100644 index ed8cc4d..0000000 --- a/src/main/java/fr/unistra/sil/erp/back/Config.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B - * https://cecill.info/licences/Licence_CeCILL-B_V1-fr.html - */ -package fr.unistra.sil.erp.back; - -/** - * Main configuration file for the application. - * @author BEAUVAIS ANTOINE - */ -public class Config { - - /** - * API version. - */ - public static final String API_VERSION = "v1"; - - /** - * Prefix for API calls. - */ - public static final String URL_PREFIX = "/api/" + API_VERSION; - - /** - * API Mapping for retrieving all items. - */ - public static final String MAPPING_RETRIEVEALL = URL_PREFIX + - "/retrieveAll"; - - /** - * API Mapping for retrieving all categories. - */ - public static final String MAPPING_GETCATEGORIES = URL_PREFIX + - "/retrieveCategories"; - - /** - * API Mapping for submitting transactions. - */ - public static final String MAPPING_SUBTRANSAC = URL_PREFIX + - "/submitTransaction"; - - /** - * API Mapping for retrieving stocks. - */ - public static final String MAPPING_GETSTOCKS = URL_PREFIX + - "/retrieveStocks"; -} diff --git a/src/main/java/fr/unistra/sil/erp/back/WebMvcConfig.java b/src/main/java/fr/unistra/sil/erp/back/WebMvcConfig.java new file mode 100644 index 0000000..9a5b3b3 --- /dev/null +++ b/src/main/java/fr/unistra/sil/erp/back/WebMvcConfig.java @@ -0,0 +1,88 @@ +/* + * CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B + * https://cecill.info/licences/Licence_CeCILL-B_V1-fr.html + */ +package fr.unistra.sil.erp.back; + +import fr.unistra.sil.erp.back.interceptor.api.ApiAuthenticationInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; +import org.springframework.core.env.Environment; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * Main configuration file for the application. + * @author BEAUVAIS ANTOINE + */ +@Configuration +@EnableWebMvc +@PropertySources( + @PropertySource("/apikey.properties") +) +public class WebMvcConfig implements WebMvcConfigurer { + + @Autowired + private Environment env; + + /** + * API version. + */ + public static final String API_VERSION = "v1"; + + /** + * API prefix. + */ + public static final String API_PREFIX = "/api/"; + + /** + * Prefix for API calls. + */ + public static final String API_FULL_PREFIX = API_PREFIX + API_VERSION; + + /** + * API Mapping for retrieving all items. + */ + public static final String MAPPING_RETRIEVEALL = API_FULL_PREFIX + + "/retrieveAll"; + + /** + * API Mapping for retrieving all categories. + */ + public static final String MAPPING_GETCATEGORIES = API_FULL_PREFIX + + "/retrieveCategories"; + + /** + * API Mapping for submitting transactions. + */ + public static final String MAPPING_SUBTRANSAC = API_FULL_PREFIX + + "/submitTransaction"; + + /** + * API Mapping for retrieving stocks. + */ + public static final String MAPPING_GETSTOCKS = API_FULL_PREFIX + + "/retrieveStocks"; + + + /* + // TODO: Define default servlet. + @Override + public void configureDefaultServletHandling( + DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + }*/ + + @Override + public void addInterceptors(InterceptorRegistry registry) { + + registry.addInterceptor(new ApiAuthenticationInterceptor( + this.env.getProperty("api.key"))) + .addPathPatterns(API_PREFIX + "**"); + + } +} diff --git a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveCategoriesController.java b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveCategoriesController.java index fa4a767..03f98dd 100644 --- a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveCategoriesController.java +++ b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveCategoriesController.java @@ -4,7 +4,7 @@ */ package fr.unistra.sil.erp.back.controller.api; -import static fr.unistra.sil.erp.back.Config.MAPPING_GETCATEGORIES; +import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_GETCATEGORIES; import fr.unistra.sil.erp.back.DatabaseSystem; import fr.unistra.sil.erp.back.controller.IRetrieveCategoriesController; import fr.unistra.sil.erp.back.model.Category; diff --git a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveInfoController.java b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveInfoController.java index ba8c6af..1c8801d 100644 --- a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveInfoController.java +++ b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveInfoController.java @@ -4,7 +4,7 @@ */ package fr.unistra.sil.erp.back.controller.api; -import static fr.unistra.sil.erp.back.Config.MAPPING_RETRIEVEALL; +import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_RETRIEVEALL; import fr.unistra.sil.erp.back.DatabaseSystem; import fr.unistra.sil.erp.back.controller.IRetrieveInfoController; import fr.unistra.sil.erp.back.model.Item; diff --git a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveStocks.java b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveStocks.java index 0e47d00..251034e 100644 --- a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveStocks.java +++ b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiRetrieveStocks.java @@ -4,7 +4,7 @@ */ package fr.unistra.sil.erp.back.controller.api; -import static fr.unistra.sil.erp.back.Config.MAPPING_GETSTOCKS; +import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_GETSTOCKS; import fr.unistra.sil.erp.back.DatabaseSystem; import fr.unistra.sil.erp.back.controller.IRetrieveStocks; import fr.unistra.sil.erp.back.db.DatabaseConnectionException; diff --git a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiSubmitTransactionController.java b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiSubmitTransactionController.java index b39c303..8396f29 100644 --- a/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiSubmitTransactionController.java +++ b/src/main/java/fr/unistra/sil/erp/back/controller/api/ApiSubmitTransactionController.java @@ -6,7 +6,7 @@ package fr.unistra.sil.erp.back.controller.api; import com.google.gson.Gson; import com.google.gson.JsonParseException; -import static fr.unistra.sil.erp.back.Config.MAPPING_SUBTRANSAC; +import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_SUBTRANSAC; import fr.unistra.sil.erp.back.DatabaseSystem; import fr.unistra.sil.erp.back.controller.ISubmitTransactionController; import fr.unistra.sil.erp.back.db.DatabaseConnectionException; diff --git a/src/main/java/fr/unistra/sil/erp/back/interceptor/api/ApiAuthenticationInterceptor.java b/src/main/java/fr/unistra/sil/erp/back/interceptor/api/ApiAuthenticationInterceptor.java new file mode 100644 index 0000000..c605793 --- /dev/null +++ b/src/main/java/fr/unistra/sil/erp/back/interceptor/api/ApiAuthenticationInterceptor.java @@ -0,0 +1,101 @@ +/* + * CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL-B + * https://cecill.info/licences/Licence_CeCILL-B_V1-fr.html + */ +package fr.unistra.sil.erp.back.interceptor.api; + +import com.google.gson.Gson; +import fr.unistra.sil.erp.back.model.ErrorMessage; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; + +/** + * API Authentication Interceptor. + * + * Each request going through an API call will be processed + * by this interceptor first. + * @author BEAUVAIS ANTOINE + */ +public class ApiAuthenticationInterceptor implements HandlerInterceptor { + + /** + * API key. + */ + private final String apikey; + + public ApiAuthenticationInterceptor(String apikey) + { + this.apikey = apikey; + } + + @Override + public boolean preHandle(HttpServletRequest request, + HttpServletResponse response, Object handler) + { + if(this.apikey == null) + { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + Gson gson = new Gson(); + ErrorMessage errMsg = new ErrorMessage("Missing API key on server"); + String responseBody = gson.toJson(errMsg); + + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + try { + PrintWriter printBody = response.getWriter(); + printBody.print(responseBody); + } catch (IOException ex) { + Logger.getLogger(ApiAuthenticationInterceptor.class.getName()) + .log(Level.SEVERE, "Failed to write body.", ex); + } + return false; + } + + String login = request.getHeader("apikey"); + if(login == null) + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + Gson gson = new Gson(); + ErrorMessage errMsg = new ErrorMessage("Missing API key."); + String responseBody = gson.toJson(errMsg); + + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + try { + PrintWriter printBody = response.getWriter(); + printBody.print(responseBody); + } catch (IOException ex) { + Logger.getLogger(ApiAuthenticationInterceptor.class.getName()) + .log(Level.SEVERE, "Failed to write body.", ex); + } + return false; + } + + if(! login.equals(this.apikey) ) + { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + Gson gson = new Gson(); + ErrorMessage errMsg = new ErrorMessage("Invalid API key."); + String responseBody = gson.toJson(errMsg); + + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + try { + PrintWriter printBody = response.getWriter(); + printBody.print(responseBody); + } catch (IOException ex) { + Logger.getLogger(ApiAuthenticationInterceptor.class.getName()) + .log(Level.SEVERE, "Failed to write body.", ex); + } + return false; + } + + return true; + } + +} -- GitLab