From 2364d10c0e88fb3144aa6eda1f3ff48d758f6061 Mon Sep 17 00:00:00 2001 From: Nikolaos Laskaris Date: Fri, 20 Oct 2017 13:03:55 +0300 Subject: [PATCH] Finalized security, distinguish between internal and external users, etc --- .../main/java/dao/entities/UserInfoDao.java | 3 ++ .../java/dao/entities/UserInfoDaoImpl.java | 34 +++++++++++++++ .../src/main/java/rest/entities/DMPs.java | 3 +- .../src/main/java/rest/entities/Datasets.java | 18 +++++++- .../src/main/java/rest/entities/Projects.java | 1 + .../CustomAuthenticationProvider.java | 10 ++--- .../validators/GoogleTokenValidator.java | 41 ++++++++++++++----- .../validators/NativeTokenValidator.java | 6 ++- .../security/validators/TokenValidator.java | 3 +- dmp-backend/src/main/webapp/WEB-INF/web.xml | 1 + 10 files changed, 97 insertions(+), 23 deletions(-) diff --git a/dmp-backend/src/main/java/dao/entities/UserInfoDao.java b/dmp-backend/src/main/java/dao/entities/UserInfoDao.java index cd4bf85c4..d97fbbb38 100644 --- a/dmp-backend/src/main/java/dao/entities/UserInfoDao.java +++ b/dmp-backend/src/main/java/dao/entities/UserInfoDao.java @@ -9,7 +9,10 @@ public interface UserInfoDao extends Dao { public UserInfo getByIdAndMail(String identification, String email); + public UserInfo getByMail(String email); public UserInfo getByAuthenticationId(String authentication); + public UserInfo getByUsername(String username); + } \ No newline at end of file diff --git a/dmp-backend/src/main/java/dao/entities/UserInfoDaoImpl.java b/dmp-backend/src/main/java/dao/entities/UserInfoDaoImpl.java index 4905d0caf..6a1a76b17 100644 --- a/dmp-backend/src/main/java/dao/entities/UserInfoDaoImpl.java +++ b/dmp-backend/src/main/java/dao/entities/UserInfoDaoImpl.java @@ -50,4 +50,38 @@ public class UserInfoDaoImpl extends JpaDao implements UserInfoD } + + @Override + public UserInfo getByMail(String email) { + String queryString = "FROM UserInfo userInfo where userInfo.email = :email"; + TypedQuery typedQuery = entityManager.createQuery(queryString, UserInfo.class); + typedQuery.setParameter("email", email); + try { + return typedQuery.getSingleResult(); + } + catch(Exception ex) { //no need to distinguish between exceptions for the moment + return null; + } + } + + + + @Override + public UserInfo getByUsername(String username) { + + String queryString = "select ui from UserInfo ui join UserAuth ui.authentication ua where ua.username=:username"; + TypedQuery typedQuery = entityManager.createQuery(queryString, UserInfo.class); + typedQuery.setParameter("username", username); + try { + return typedQuery.getSingleResult(); + } + catch(Exception ex) { //no need to distinguish between exceptions for the moment + return null; + } + } + + + + + } \ No newline at end of file diff --git a/dmp-backend/src/main/java/rest/entities/DMPs.java b/dmp-backend/src/main/java/rest/entities/DMPs.java index c7bb4a4ce..179ad8508 100644 --- a/dmp-backend/src/main/java/rest/entities/DMPs.java +++ b/dmp-backend/src/main/java/rest/entities/DMPs.java @@ -241,6 +241,7 @@ public class DMPs { dMPDao.delete(d); return ResponseEntity.status(HttpStatus.CREATED).body("DELETED!"); } catch (Exception e) { + e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"msg\":\"Could not Delete DMP!\""); } @@ -249,8 +250,6 @@ public class DMPs { - - // OLD ONES, USED BY THE EMBEDDED (simple) UI OF THIS SERVICE @RequestMapping(method = RequestMethod.POST, value = { "/setDMPByForm" }, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces="text/plain") public @ResponseBody ResponseEntity setDMPByForm(@RequestBody MultiValueMap formData) { diff --git a/dmp-backend/src/main/java/rest/entities/Datasets.java b/dmp-backend/src/main/java/rest/entities/Datasets.java index 2cad4479b..f8f4352f8 100644 --- a/dmp-backend/src/main/java/rest/entities/Datasets.java +++ b/dmp-backend/src/main/java/rest/entities/Datasets.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.PrintStream; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import javax.transaction.Transactional; @@ -45,6 +46,7 @@ import entities.Dataset; import entities.DatasetProfile; import entities.DatasetProfileRuleset; import entities.DatasetProfileViewstyle; +import entities.Organisation; import entities.Project; import helpers.Transformers; import responses.RestResponse; @@ -101,13 +103,25 @@ public class Datasets { */ @RequestMapping(method = RequestMethod.GET, value = { "/getAllDatasets" }) public @ResponseBody ResponseEntity getAllDatasets(){ + try { List allDatasets = datasetDao.getAll(); - return ResponseEntity.status(HttpStatus.OK).body(new ObjectMapper().writeValueAsString(allDatasets)); + + //sorry for that, spring-jersey serialisation has issues when performed on tables, so -> custom + List datasetsStrL = allDatasets.parallelStream().map((datasetObj) -> { + try { + return objectMapper.writeValueAsString(datasetObj); + } catch (JsonProcessingException e) { + return ""; + } + }).collect(Collectors.toList()); + + return new ResponseEntity("["+String.join(",", datasetsStrL)+"]", HttpStatus.OK); } catch(Exception ex) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Serialization issue: "+ex.getMessage()); + return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); } + } diff --git a/dmp-backend/src/main/java/rest/entities/Projects.java b/dmp-backend/src/main/java/rest/entities/Projects.java index 5c806d605..04246a58d 100644 --- a/dmp-backend/src/main/java/rest/entities/Projects.java +++ b/dmp-backend/src/main/java/rest/entities/Projects.java @@ -154,6 +154,7 @@ public class Projects { projectDao.delete(p); return ResponseEntity.status(HttpStatus.CREATED).body("{\"msg\":\"Deleted Project entity!\"}"); } catch (Exception e) { + e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"msg\":\"Could not Delete Project!\"}"); } diff --git a/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java b/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java index 4094e9c7b..3a87b19fa 100644 --- a/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java +++ b/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java @@ -44,18 +44,14 @@ public class CustomAuthenticationProvider implements AuthenticationProvider { else throw new AuthenticationServiceException("The appropriate http headers have not been set. Please check!"); - + UserInfo userInfo; try { - tokenValidator.validateToken(token); + userInfo = tokenValidator.validateToken(token); } catch (NonValidTokenException e) { System.out.println("Could not validate a user by his token! Reason: "+e.getMessage()); throw new AuthenticationServiceException("Token validation failed - Not a valid token"); } - - //store to database if new -// UserInfo existingUserInfo = userInfoDao.getByKey(userInfo.getId(), userInfo.getEmail()); -// if(existingUserInfo == null) -// userInfoDao.create(userInfo); + // if reached this point, authentication is ok, so return just an instance with whatever. return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), new ArrayList<>()); diff --git a/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java b/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java index 04884cac3..f04156d65 100644 --- a/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java +++ b/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java @@ -3,8 +3,11 @@ package security.validators; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Arrays; +import java.util.Date; import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; + import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload; @@ -12,6 +15,7 @@ import com.google.api.client.http.HttpTransport; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; +import dao.entities.UserInfoDao; import entities.UserInfo; import exceptions.NonValidTokenException; @@ -20,9 +24,12 @@ public class GoogleTokenValidator implements TokenValidator { private static final JacksonFactory jacksonFactory = new JacksonFactory(); private static final HttpTransport transport = new NetHttpTransport(); + @Autowired private UserInfoDao userInfoDao; + + private static final List clientIDs = Arrays.asList( "1010962018903-glegmqudqtl1lub0150vacopbu06lgsg.apps.googleusercontent.com", - "" + "1010962018903-glegmqudqtl1lub0150vacopbu06lgsg.apps.googleusercontent.com" ); private GoogleIdTokenVerifier verifier = null; @@ -38,7 +45,7 @@ public class GoogleTokenValidator implements TokenValidator { @Override - public void validateToken(String token) throws NonValidTokenException { + public UserInfo validateToken(String token) throws NonValidTokenException { GoogleIdToken idToken = null; try { @@ -57,15 +64,29 @@ public class GoogleTokenValidator implements TokenValidator { if(idToken == null) { throw new NonValidTokenException("Not a valid token"); } -// else { -// Payload payload = idToken.getPayload(); -// UserInfo userInfo = new UserInfo(payload.getSubject(), payload.getEmail(), -// payload.getEmailVerified(), (String)payload.get("name"), (String)payload.get("picture"), -// (String)payload.get("locale"), (String)payload.get("family_name"), (String)payload.get("given_name"), ""); -// System.out.println(userInfo.toString()); -// return userInfo; -// } + + Payload payload = idToken.getPayload(); + + UserInfo userInfo = userInfoDao.getByMail(payload.getEmail()); + + if(userInfo == null) { //means not existing in db, so create one + userInfo = new UserInfo(); + userInfo.setName((String)payload.get("name")); + userInfo.setVerified_email(payload.getEmailVerified()); + userInfo.setEmail(payload.getEmail()); + userInfo.setCreated(new Date()); + userInfo.setLastloggedin(new Date()); + userInfo.setAuthorization_level(new Short("1")); + userInfo.setUsertype(new Short("1")); + userInfo = userInfoDao.create(userInfo); + } + else { + userInfo.setLastloggedin(new Date()); + userInfo = userInfoDao.update(userInfo); + } + return userInfo; + } diff --git a/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java b/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java index 65494cd2d..fd35a3f24 100644 --- a/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java +++ b/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java @@ -2,18 +2,22 @@ package security.validators; import org.springframework.beans.factory.annotation.Autowired; +import dao.entities.UserInfoDao; +import entities.UserInfo; import exceptions.NonValidTokenException; import security.TokenSessionManager; public class NativeTokenValidator implements TokenValidator { @Autowired private TokenSessionManager tokenSessionManager; + @Autowired private UserInfoDao userInfoDao; @Override - public void validateToken(String token) throws NonValidTokenException { + public UserInfo validateToken(String token) throws NonValidTokenException { String tokenUser = tokenSessionManager.getUser(token); if(tokenUser==null || tokenUser.isEmpty()) throw new NonValidTokenException("Login session has expired! Need to login again!"); + return userInfoDao.getByUsername(tokenUser); } diff --git a/dmp-backend/src/main/java/security/validators/TokenValidator.java b/dmp-backend/src/main/java/security/validators/TokenValidator.java index 65a7a6710..266106378 100644 --- a/dmp-backend/src/main/java/security/validators/TokenValidator.java +++ b/dmp-backend/src/main/java/security/validators/TokenValidator.java @@ -1,9 +1,10 @@ package security.validators; +import entities.UserInfo; import exceptions.NonValidTokenException; public interface TokenValidator { - public void validateToken(String token) throws NonValidTokenException; + public UserInfo validateToken(String token) throws NonValidTokenException; } diff --git a/dmp-backend/src/main/webapp/WEB-INF/web.xml b/dmp-backend/src/main/webapp/WEB-INF/web.xml index 13fdb5e4c..6de4a1563 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/web.xml +++ b/dmp-backend/src/main/webapp/WEB-INF/web.xml @@ -68,6 +68,7 @@ contextConfigLocation /WEB-INF/applicationContext.xml,/WEB-INF/spring-security.xml + 30