From 6e5466f44480a5e5bcd5db0aae81e47ad39282f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Guimar=C3=A3es?= Date: Mon, 23 Nov 2015 18:38:45 -0200 Subject: [PATCH] #9 Added controller restriction based on the token verification. Improved JSON error messaging with ErrorResult class. Version set as context on application.properties. Fixed some class headers with code license and improved class and method comments. --- .../api/controller/InterfaceController.java | 39 ++++- .../api/controller/OccurrenceController.java | 56 +++++--- .../api/controller/ResourceController.java | 69 +++++---- .../api/controller/StatisticsController.java | 135 ++++++++++++++---- .../br/gov/sibbr/api/db/DatabaseAuth.java | 46 +++++- .../gov/sibbr/api/db/DatabaseConnection.java | 6 +- .../br/gov/sibbr/api/db/DatabaseQueries.java | 20 +++ src/main/java/br/gov/sibbr/api/db/Utils.java | 17 ++- .../br/gov/sibbr/api/model/ErrorResult.java | 39 +++++ .../br/gov/sibbr/api/model/LoginForm.java | 15 ++ .../gov/sibbr/api/model/OccurrenceResult.java | 20 ++- .../br/gov/sibbr/api/model/StatsResult.java | 8 ++ .../br/gov/sibbr/api/service/AuthService.java | 52 +++++++ src/main/resources/application.properties | 15 +- .../resources/templates/login_success.html | 6 +- 15 files changed, 423 insertions(+), 120 deletions(-) create mode 100644 src/main/java/br/gov/sibbr/api/model/ErrorResult.java diff --git a/src/main/java/br/gov/sibbr/api/controller/InterfaceController.java b/src/main/java/br/gov/sibbr/api/controller/InterfaceController.java index 1255771..87179a0 100644 --- a/src/main/java/br/gov/sibbr/api/controller/InterfaceController.java +++ b/src/main/java/br/gov/sibbr/api/controller/InterfaceController.java @@ -21,17 +21,16 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import br.gov.sibbr.api.Application; import br.gov.sibbr.api.model.LoginForm; import br.gov.sibbr.api.service.AuthService; -@Controller /** * Controller for the general html templates. * * @author Pedro Guimarães * */ +@Controller public class InterfaceController implements ErrorController { private final String ERROR_PATH = "/erro"; @@ -41,14 +40,13 @@ public class InterfaceController implements ErrorController { // Method responsible for managing occurrence requests @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(LoginForm loginForm, Model model) { - // TODO: receber e validar a lista de parâmetros, conectar ao banco de - // dados para verificar usuário e senha String email = loginForm.getEmail(); String password = loginForm.getPassword(); if (email != null && password != null) { String message = authService.checkPassword(email, password); if (message == null) { - // Successful authentication with valid credentials, fetch user token: + // Successful authentication with valid credentials, fetch user + // token: String token = authService.fetchToken(email); if (token != null) { model.addAttribute("token", token); @@ -60,19 +58,46 @@ public String login(LoginForm loginForm, Model model) { return "login_fail"; } + // Method responsible for managing occurrence requests + @RequestMapping(value = "/admin", method = RequestMethod.POST) + public String admin(LoginForm loginForm, Model model) { + String email = loginForm.getEmail(); + String password = loginForm.getPassword(); + if (email != null && password != null) { + String message = authService.checkPassword(email, password); + if (message == null) { + // Successful authentication with valid credentials, fetch user + // token: + String token = authService.fetchToken(email); + if (token != null) { + model.addAttribute("token", token); + return "admin_login_success"; + } + } + model.addAttribute("message", message); + } + return "admin_login_fail"; + } + @RequestMapping("/") public String greeting(Model model) { return "index"; } // Method responsible for calling the login template - @RequestMapping(value ="/login", method = RequestMethod.GET) + @RequestMapping(value = "/login", method = RequestMethod.GET) public String login() { return "login"; } + // Method responsible for calling the login template + @RequestMapping(value = "/admin", method = RequestMethod.GET) + public String admin() { + return "admin"; + } + // Method responsible for managing occurrence requests - @RequestMapping(value ="/stats", method = RequestMethod.GET) + @RequestMapping(value = "/stats", method = RequestMethod.GET) public String stats() { return "stats"; } diff --git a/src/main/java/br/gov/sibbr/api/controller/OccurrenceController.java b/src/main/java/br/gov/sibbr/api/controller/OccurrenceController.java index 7c3233b..19aecfa 100644 --- a/src/main/java/br/gov/sibbr/api/controller/OccurrenceController.java +++ b/src/main/java/br/gov/sibbr/api/controller/OccurrenceController.java @@ -23,10 +23,11 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import br.gov.sibbr.api.model.ErrorResult; import br.gov.sibbr.api.model.OccurrenceResult; +import br.gov.sibbr.api.service.AuthService; import br.gov.sibbr.api.service.DatabaseService; -@RestController /** * Controller responsible for managing URL requests and calling for services to * provide occurrence data @@ -34,40 +35,49 @@ * @author Pedro Guimarães * */ +@RestController public class OccurrenceController { - // Auxiliary service class - DatabaseService service = new DatabaseService(); + // Auxiliary service classes + DatabaseService databaseService = new DatabaseService(); + AuthService authService = new AuthService(); // Method responsible for managing occurrence requests @Cacheable("occurrence") @RequestMapping(value = "/ocorrencias", method = RequestMethod.GET) - public OccurrenceResult occurrence( + public Object occurrence( @RequestParam(value = "scientificname", defaultValue = "null") String scientificname, @RequestParam(value = "ignoreNullCoordinates", defaultValue = "false") String ignorenullcoordinates, @RequestParam(value = "limit", defaultValue = "0") String limit, - @RequestParam(value = "fields", defaultValue = "0") String fields) { + @RequestParam(value = "fields", defaultValue = "0") String fields, + @RequestParam(value = "token", defaultValue = "null") String token) { Long startTimeInMs = System.currentTimeMillis(); int intLimit = Integer.parseInt(limit); int intFields = Integer.parseInt(fields); - // Avoid returning all records when no filter is provided - if (!scientificname.equalsIgnoreCase("null")) { - if (ignorenullcoordinates.equalsIgnoreCase("false")) { - ArrayList occurrences = service.fetchOccurrences( - scientificname, false, intLimit, intFields); - Long totalTimeInMs = service.calculateTimeLapse(startTimeInMs, - System.currentTimeMillis()); - return new OccurrenceResult(scientificname, occurrences, - totalTimeInMs); - } else if (ignorenullcoordinates.equalsIgnoreCase("true")) { - ArrayList occurrences = service.fetchOccurrences( - scientificname, true, intLimit, intFields); - Long totalTimeInMs = service.calculateTimeLapse(startTimeInMs, - System.currentTimeMillis()); - return new OccurrenceResult(scientificname, occurrences, - totalTimeInMs); + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + // Avoid returning all records when no filter is provided + if (!scientificname.equalsIgnoreCase("null")) { + if (ignorenullcoordinates.equalsIgnoreCase("false")) { + ArrayList occurrences = databaseService.fetchOccurrences(scientificname, false, intLimit, + intFields); + Long totalTimeInMs = databaseService.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); + return new OccurrenceResult(scientificname, occurrences, totalTimeInMs); + } else if (ignorenullcoordinates.equalsIgnoreCase("true")) { + ArrayList occurrences = databaseService.fetchOccurrences(scientificname, true, intLimit, + intFields); + Long totalTimeInMs = databaseService.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); + return new OccurrenceResult(scientificname, occurrences, totalTimeInMs); + } } + // No scientificname provided: + return new ErrorResult("No scientific name provided for the search"); } - return new OccurrenceResult(); + // The user has bad token authentication, display error message: + else { + return new ErrorResult(tokenCheck); + } } -} +} \ No newline at end of file diff --git a/src/main/java/br/gov/sibbr/api/controller/ResourceController.java b/src/main/java/br/gov/sibbr/api/controller/ResourceController.java index 35eee23..10bcd86 100644 --- a/src/main/java/br/gov/sibbr/api/controller/ResourceController.java +++ b/src/main/java/br/gov/sibbr/api/controller/ResourceController.java @@ -18,60 +18,81 @@ import java.util.ArrayList; import org.springframework.cache.annotation.Cacheable; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import br.gov.sibbr.api.model.ErrorResult; import br.gov.sibbr.api.model.OccurrenceResult; import br.gov.sibbr.api.model.Resource; import br.gov.sibbr.api.model.ResourceResult; +import br.gov.sibbr.api.service.AuthService; import br.gov.sibbr.api.service.DatabaseService; @RestController +/** + * Controller class for the management of all resource related calls to the API + * @author Pedro Guimarães + * + */ public class ResourceController { // Auxiliary service class - DatabaseService service = new DatabaseService(); + DatabaseService databaseService = new DatabaseService(); + AuthService authService = new AuthService(); @RequestMapping(value = "/recursos", method = RequestMethod.GET) - public ResourceResult resources(Model model) { - Long startTimeInMs = System.currentTimeMillis(); - ArrayList resources = service.fetchResources(); - Long totalTimeInMs = service.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); - ResourceResult resourceResult = new ResourceResult(resources, totalTimeInMs); - return resourceResult; + public Object resources(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + + Long startTimeInMs = System.currentTimeMillis(); + ArrayList resources = databaseService.fetchResources(); + Long totalTimeInMs = databaseService.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); + ResourceResult resourceResult = new ResourceResult(resources, totalTimeInMs); + return resourceResult; + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests with resource // filtering @Cacheable("resource_occurrence") @RequestMapping(value = "/recursos/{id}/ocorrencias", method = RequestMethod.GET) - public OccurrenceResult occurrencesByResource( - @PathVariable String id, + public Object occurrencesByResource(@PathVariable String id, @RequestParam(value = "scientificname", defaultValue = "") String scientificname, @RequestParam(value = "ignoreNullCoordinates", defaultValue = "false") String ignorenullcoordinates, @RequestParam(value = "limit", defaultValue = "0") String limit, - @RequestParam(value = "fields", defaultValue = "0") String fields) { + @RequestParam(value = "fields", defaultValue = "0") String fields, + @RequestParam(value = "token", defaultValue = "null") String token) { Long startTimeInMs = System.currentTimeMillis(); int intResourceId = Integer.parseInt(id); int intLimit = Integer.parseInt(limit); int intFields = Integer.parseInt(fields); - if (ignorenullcoordinates.equalsIgnoreCase("false")) { - ArrayList occurrences = service.fetchOccurrencesByResource(scientificname, false, - intLimit, intFields, intResourceId); - Long totalTimeInMs = service.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); - return new OccurrenceResult(scientificname, occurrences, totalTimeInMs - ); - } else if (ignorenullcoordinates.equalsIgnoreCase("true")) { - ArrayList occurrences = service.fetchOccurrencesByResource(scientificname, true, - intLimit, intFields, intResourceId); - Long totalTimeInMs = service.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); - return new OccurrenceResult(scientificname, occurrences, totalTimeInMs - ); + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + if (ignorenullcoordinates.equalsIgnoreCase("false")) { + ArrayList occurrences = databaseService.fetchOccurrencesByResource(scientificname, false, intLimit, + intFields, intResourceId); + Long totalTimeInMs = databaseService.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); + return new OccurrenceResult(scientificname, occurrences, totalTimeInMs); + } else if (ignorenullcoordinates.equalsIgnoreCase("true")) { + ArrayList occurrences = databaseService.fetchOccurrencesByResource(scientificname, true, intLimit, + intFields, intResourceId); + Long totalTimeInMs = databaseService.calculateTimeLapse(startTimeInMs, System.currentTimeMillis()); + return new OccurrenceResult(scientificname, occurrences, totalTimeInMs); + } + } + // The user has bad token authentication, display error message: + else { + return new ErrorResult(tokenCheck); } - return new OccurrenceResult(); + return new ErrorResult("No scientific name provided for the search"); } } \ No newline at end of file diff --git a/src/main/java/br/gov/sibbr/api/controller/StatisticsController.java b/src/main/java/br/gov/sibbr/api/controller/StatisticsController.java index 3303a86..fdffd87 100644 --- a/src/main/java/br/gov/sibbr/api/controller/StatisticsController.java +++ b/src/main/java/br/gov/sibbr/api/controller/StatisticsController.java @@ -1,98 +1,181 @@ +/** + SiBBr API - Interface pública de acesso aos registros de ocorrência + Copyright (C) 2015 SiBBr - Sistema de Informação sobre a Biodiversidade Brasileira + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + package br.gov.sibbr.api.controller; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import br.gov.sibbr.api.Application; -import br.gov.sibbr.api.model.StatsResult; +import br.gov.sibbr.api.model.ErrorResult; +import br.gov.sibbr.api.service.AuthService; import br.gov.sibbr.api.service.DatabaseService; -@RestController /** * Controller responsible for managing statistics requests to the database * * @author Pedro Guimarães * */ +@RestController public class StatisticsController { // Auxiliary service class - DatabaseService service = new DatabaseService(); + DatabaseService databaseService = new DatabaseService(); + AuthService authService = new AuthService(); // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalRegistros", method = RequestMethod.GET) @Cacheable("total_records") - public StatsResult fetchTotalRecords() { - return service.fetchTotalRecords(); + public Object fetchTotalRecords(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalRecords(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalRegistrosGeorreferenciados", method = RequestMethod.GET) @Cacheable("total_geo_records") - public StatsResult fetchTotalGeoRecords() { - return service.fetchTotalGeoRecords(); + public Object fetchTotalGeoRecords(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalGeoRecords(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalRegistrosRepatriados", method = RequestMethod.GET) @Cacheable("total_repatriados") - public StatsResult fetchTotalRepatriatedRecords() { - return service.fetchTotalRepatriatedRecords(); + public Object fetchTotalRepatriatedRecords(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalRepatriatedRecords(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalPublicadores", method = RequestMethod.GET) - public StatsResult fetchTotalPublishers() { - return service.fetchTotalPublishers(); + public Object fetchTotalPublishers(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalPublishers(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalRecursos", method = RequestMethod.GET) - public StatsResult fetchTotalResources() { - return service.fetchTotalResources(); + public Object fetchTotalResources(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalResources(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalEspecies", method = RequestMethod.GET) @Cacheable("total_species") - public StatsResult fetchTotalSpecies() { - return service.fetchTotalSpecies(); + public Object fetchTotalSpecies(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalSpecies(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalFilo", method = RequestMethod.GET) @Cacheable("total_phylum") - public StatsResult fetchTotalPhylum() { - return service.fetchTotalPhylum(); + public Object fetchTotalPhylum(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalPhylum(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalClasse", method = RequestMethod.GET) @Cacheable("total_class") - public StatsResult fetchTotalClass() { - return service.fetchTotalClass(); + public Object fetchTotalClass(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalClass(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalOrdem", method = RequestMethod.GET) @Cacheable("total_order") - public StatsResult fetchTotalOrder() { - return service.fetchTotalOrder(); + public Object fetchTotalOrder(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalOrder(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalGenero", method = RequestMethod.GET) @Cacheable("total_genus") - public StatsResult fetchTotalGenus() { - return service.fetchTotalGenus(); + public Object fetchTotalGenus(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalGenus(); + } + return new ErrorResult(tokenCheck); } // Method responsible for managing occurrence requests @RequestMapping(value = "/stats/totalFamilia", method = RequestMethod.GET) @Cacheable("total_family") - public StatsResult fetchTotalFamily() { - return service.fetchTotalFamily(); + public Object fetchTotalFamily(@RequestParam(value = "token", defaultValue = "null") String token) { + // Check of the user has proper access grant token + String tokenCheck = authService.checkToken(token); + // If user provided a valid token, proceed: + if (tokenCheck == null) { + return databaseService.fetchTotalFamily(); + } + return new ErrorResult(tokenCheck); } } \ No newline at end of file diff --git a/src/main/java/br/gov/sibbr/api/db/DatabaseAuth.java b/src/main/java/br/gov/sibbr/api/db/DatabaseAuth.java index 3d6b088..1dfad67 100644 --- a/src/main/java/br/gov/sibbr/api/db/DatabaseAuth.java +++ b/src/main/java/br/gov/sibbr/api/db/DatabaseAuth.java @@ -1,3 +1,18 @@ +/** + SiBBr API - Interface pública de acesso aos registros de ocorrência + Copyright (C) 2015 SiBBr - Sistema de Informação sobre a Biodiversidade Brasileira + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + package br.gov.sibbr.api.db; import java.sql.Connection; @@ -5,6 +20,13 @@ import java.sql.SQLException; import java.sql.Statement; +/** + * This class is responsible for providing database access methods to query the + * authentication database + * + * @author pedro + * + */ public class DatabaseAuth { private Connection conn = null; @@ -31,6 +53,26 @@ public DatabaseAuth() throws Exception { } } + /** + * Fetches records from dataportal schema, returning different sets of + * fields from occurrence table that match the given scientificname; + * + * @param scientificname + * @return + */ + public ResultSet queryToken(String token) { + ResultSet resultSet = null; + Statement statement = null; + try { + statement = conn.createStatement(); + resultSet = statement.executeQuery( + "SELECT * FROM " + API_TOKEN_TABLE + " WHERE " + API_TOKEN_TOKEN + " = \'" + token + "\'"); + } catch (SQLException e) { + e.printStackTrace(); + } + return resultSet; + } + /** * Fetches records from dataportal schema, returning different sets of * fields from occurrence table that match the given scientificname; @@ -60,8 +102,8 @@ public ResultSet queryApiUser(String email) { public ResultSet queryApiUserTokenId(String email) { ResultSet resultSet = null; Statement statement = null; - String sql = "SELECT " + API_USER_TOKEN_ID + " FROM " + API_USER_TABLE + " WHERE " - + API_USER_EMAIL + " = \'" + email + "\'"; + String sql = "SELECT " + API_USER_TOKEN_ID + " FROM " + API_USER_TABLE + " WHERE " + API_USER_EMAIL + " = \'" + + email + "\'"; try { statement = conn.createStatement(); resultSet = statement.executeQuery(sql); diff --git a/src/main/java/br/gov/sibbr/api/db/DatabaseConnection.java b/src/main/java/br/gov/sibbr/api/db/DatabaseConnection.java index ba3912e..90cd8fa 100644 --- a/src/main/java/br/gov/sibbr/api/db/DatabaseConnection.java +++ b/src/main/java/br/gov/sibbr/api/db/DatabaseConnection.java @@ -19,10 +19,6 @@ import java.sql.DriverManager; import java.sql.SQLException; -import org.springframework.beans.factory.annotation.Value; - -import br.gov.sibbr.api.Application; - /** * This class is responsible to manage jdbc connections to the postgresql * database only for read operations. @@ -40,7 +36,7 @@ public class DatabaseConnection { public static String authUrl = "jdbc:postgresql://localhost/dataportal_auth"; public static String authUser = "dbadmin"; public static String authPassword = "dbadmin"; - + /** * Singleton to connect to database * diff --git a/src/main/java/br/gov/sibbr/api/db/DatabaseQueries.java b/src/main/java/br/gov/sibbr/api/db/DatabaseQueries.java index 5a5c8e3..a27987b 100644 --- a/src/main/java/br/gov/sibbr/api/db/DatabaseQueries.java +++ b/src/main/java/br/gov/sibbr/api/db/DatabaseQueries.java @@ -1,3 +1,18 @@ +/** + SiBBr API - Interface pública de acesso aos registros de ocorrência + Copyright (C) 2015 SiBBr - Sistema de Informação sobre a Biodiversidade Brasileira + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + package br.gov.sibbr.api.db; import java.sql.Connection; @@ -5,6 +20,11 @@ import java.sql.SQLException; import java.sql.Statement; +/** + * This class is responsible for providing access methods to the database through query implementations + * @author Pedro Guimarães + * + */ public class DatabaseQueries { private Connection conn = null; diff --git a/src/main/java/br/gov/sibbr/api/db/Utils.java b/src/main/java/br/gov/sibbr/api/db/Utils.java index 8a275bf..435a36c 100644 --- a/src/main/java/br/gov/sibbr/api/db/Utils.java +++ b/src/main/java/br/gov/sibbr/api/db/Utils.java @@ -19,6 +19,11 @@ import java.sql.SQLException; import java.sql.Timestamp; +/** + * Auxiliary class with a series of helpful auxiliary methods + * @author Pedro Guimarães + * + */ public class Utils { /** @@ -34,29 +39,29 @@ public static Double getDouble(ResultSet rs, String strColName) throws SQLExcept double nValue = rs.getDouble(strColName); return rs.wasNull() ? null : nValue; } - + /** - * Auxiliary method to avoid problems with null values - * is null + * Auxiliary method to avoid problems with null values is null * * @param rs * @param strColName * @return * @throws SQLException */ - public static String getString (ResultSet rs, String strColName) throws SQLException { + public static String getString(ResultSet rs, String strColName) throws SQLException { String value = rs.getString(strColName); return rs.wasNull() ? null : value; } - + /** * Auxiliary method to avoid problems with null timestamp values + * * @param rs * @param strColName * @return * @throws SQLException */ - public static Timestamp getTimestamp (ResultSet rs, String strColName) throws SQLException { + public static Timestamp getTimestamp(ResultSet rs, String strColName) throws SQLException { Timestamp value = rs.getTimestamp(strColName); return rs.wasNull() ? null : value; } diff --git a/src/main/java/br/gov/sibbr/api/model/ErrorResult.java b/src/main/java/br/gov/sibbr/api/model/ErrorResult.java new file mode 100644 index 0000000..7932f9d --- /dev/null +++ b/src/main/java/br/gov/sibbr/api/model/ErrorResult.java @@ -0,0 +1,39 @@ +/** + SiBBr API - Interface pública de acesso aos registros de ocorrência + Copyright (C) 2015 SiBBr - Sistema de Informação sobre a Biodiversidade Brasileira + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + +package br.gov.sibbr.api.model; + +/** + * Simple class to output error messages as JSON results + * @author Pedro Guimarães + * + */ +public class ErrorResult { + + // Error messages + private String error; + + public ErrorResult(String error) { + this.error = error; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } +} diff --git a/src/main/java/br/gov/sibbr/api/model/LoginForm.java b/src/main/java/br/gov/sibbr/api/model/LoginForm.java index 8804795..cde0e0f 100644 --- a/src/main/java/br/gov/sibbr/api/model/LoginForm.java +++ b/src/main/java/br/gov/sibbr/api/model/LoginForm.java @@ -1,3 +1,18 @@ +/** + SiBBr API - Interface pública de acesso aos registros de ocorrência + Copyright (C) 2015 SiBBr - Sistema de Informação sobre a Biodiversidade Brasileira + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + package br.gov.sibbr.api.model; /** diff --git a/src/main/java/br/gov/sibbr/api/model/OccurrenceResult.java b/src/main/java/br/gov/sibbr/api/model/OccurrenceResult.java index dc5940d..0d95aeb 100644 --- a/src/main/java/br/gov/sibbr/api/model/OccurrenceResult.java +++ b/src/main/java/br/gov/sibbr/api/model/OccurrenceResult.java @@ -37,17 +37,7 @@ public class OccurrenceResult { // The amount of time that took the query in milliseconds private Long queryLength; - - /* - * Default constructor for queries where no scientific name is provided for the occurrence search - */ - public OccurrenceResult() { - this.scientificname = "No scientific name provided for the search"; - this.count = 0; - this.occurrences = null; - this.queryLength = new Long(0); - } - + /** * Default constructor * @param scientificname @@ -91,4 +81,12 @@ public ArrayList getOccurrences() { public void setOccurrences(ArrayList occurrences) { this.occurrences = occurrences; } + + public String getScientificname() { + return scientificname; + } + + public void setScientificname(String scientificname) { + this.scientificname = scientificname; + } } \ No newline at end of file diff --git a/src/main/java/br/gov/sibbr/api/model/StatsResult.java b/src/main/java/br/gov/sibbr/api/model/StatsResult.java index 8f0f9a1..6a1979b 100644 --- a/src/main/java/br/gov/sibbr/api/model/StatsResult.java +++ b/src/main/java/br/gov/sibbr/api/model/StatsResult.java @@ -44,4 +44,12 @@ public Integer getAmount() { public void setAmount(Integer amount) { this.amount = amount; } + + public Long getQueryLength() { + return queryLength; + } + + public void setQueryLength(Long queryLength) { + this.queryLength = queryLength; + } } diff --git a/src/main/java/br/gov/sibbr/api/service/AuthService.java b/src/main/java/br/gov/sibbr/api/service/AuthService.java index 052e001..22c1520 100644 --- a/src/main/java/br/gov/sibbr/api/service/AuthService.java +++ b/src/main/java/br/gov/sibbr/api/service/AuthService.java @@ -1,3 +1,18 @@ +/** + SiBBr API - Interface pública de acesso aos registros de ocorrência + Copyright (C) 2015 SiBBr - Sistema de Informação sobre a Biodiversidade Brasileira + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + package br.gov.sibbr.api.service; import java.security.MessageDigest; @@ -13,6 +28,11 @@ import br.gov.sibbr.api.db.DatabaseAuth; import br.gov.sibbr.api.db.Utils; +/** + * Service class for all authentication related methods + * @author Pedro Guimarães + * + */ public class AuthService { public static char[] hexDigit = "0123456789abcdef".toCharArray(); @@ -105,6 +125,38 @@ public String checkPassword(String email, String password) { } return "Invalid e-mail address."; } + + /** + * Check if the provided token is valid and not expired. + * @param token + * @return error messages or null if the token is valid. + */ + public String checkToken(String token) { + ResultSet rs = dba.queryToken(token); + if (rs != null) { + HashMap hashMap = processApiToken(rs); + if (hashMap.size() > 0) { + token = (String) hashMap.get("token"); + // Get date string: + Timestamp tokenTime = (Timestamp) hashMap.get("created_at"); + // Get current date: + Date currentTime = Calendar.getInstance().getTime(); + // Check if the token has more than 7 days from creation to + // now, being therefore, expired + long diff = Math.abs(currentTime.getTime() - tokenTime.getTime()); + long diffInMinutes = diff / (60 * 1000); + // Amount of minutes in one week + long weekInMinutes = 60 * 24 * 7; + // If the token is one week + old, generate a new token + if (diffInMinutes > weekInMinutes) { + return "Expired token. Please login and fetch a new token."; + } + // Valid and non expired token: + return null; + } + } + return "Invalid token."; + } /** * Returns the user a valid token. If the current token is expired, diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 741124d..c198fa1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,16 +1,5 @@ -# Set the port for your application to listen to: -# server.port=9666 - -# Database connection information: -data.url=jdbc:postgresql://localhost/dataportal -data.username=dbadmin -data.password=dbadmin - -# Database auth connection information -auth.url=jdbc:postgresql://localhost/dataportal_auth -auth.username=dbadmin -auth.password=dbadmin - +# Api version +server.contextPath=/v1.1 # SSL set up: server.port=8444 server.ssl.key-store=keystore.p12 diff --git a/src/main/resources/templates/login_success.html b/src/main/resources/templates/login_success.html index 3626293..84efe6c 100644 --- a/src/main/resources/templates/login_success.html +++ b/src/main/resources/templates/login_success.html @@ -2,7 +2,7 @@ - Login page + Login realizado com sucesso || Login success

Português

@@ -10,7 +10,7 @@

Português

Token de acesso:

-

Use este token como o parâmetro apiKey em cada requisição à API.

+

Use este token como o parâmetro token em cada requisição à API.

Nota: Não compartilhe este token com outros, pois ele representa os acessos realizados à API pelo seu usuário. Este token é válido por 7 dias.

Depois deste período, você deve se identificar novamente para receber um novo token.

English

@@ -18,7 +18,7 @@

English

Access token:

-

Use this token as the apiKey parameter in every API request.

+

Use this token as the token parameter in every API request.

Note: Do not share this token with others, as it represents the accesses your user makes to the API. This token is valid for 7 days.

After that period, you should login once again in order to fetch a new token.