diff --git a/dmp-backend/pom.xml b/dmp-backend/pom.xml
index db2246392..ef61d55b6 100644
--- a/dmp-backend/pom.xml
+++ b/dmp-backend/pom.xml
@@ -256,6 +256,15 @@
+
+
+ com.google.guava
+ guava
+ 23.0
+
+
+
+
org.apache.commons
diff --git a/dmp-backend/src/main/java/checks/EnvironmentChecker.java b/dmp-backend/src/main/java/checks/EnvironmentChecker.java
new file mode 100644
index 000000000..fe70e6227
--- /dev/null
+++ b/dmp-backend/src/main/java/checks/EnvironmentChecker.java
@@ -0,0 +1,31 @@
+package checks;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+public class EnvironmentChecker implements ServletContextListener {
+
+ @Override
+ public void contextDestroyed(ServletContextEvent arg0) {
+
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent arg0) {
+ try{
+ MessageDigest.getInstance("SHA-256");
+ System.out.println("SHA-256 algorithm found, as expected!");
+ }
+ catch(NoSuchAlgorithmException ex) {
+ System.out.println("\n\n\n\nSEVERE ERROR: COULD NOT FIND WITHIN JVM THE SHA-256 ALGORITHM. PLEASE UPDATE THE JRE TO A VERSION >= 1.7\n\n\n\n");
+ //shutting down the webapp should also be considered
+ }
+
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/dmp-backend/src/main/java/dao/entities/security/UserAuthDao.java b/dmp-backend/src/main/java/dao/entities/security/UserAuthDao.java
index 3fee4f35f..d64266420 100644
--- a/dmp-backend/src/main/java/dao/entities/security/UserAuthDao.java
+++ b/dmp-backend/src/main/java/dao/entities/security/UserAuthDao.java
@@ -10,5 +10,6 @@ public interface UserAuthDao extends Dao {
public String getPasswordHashOfUser(String username);
+ public UserAuth getUserAuthBy(String username);
}
diff --git a/dmp-backend/src/main/java/dao/entities/security/UserAuthDaoImpl.java b/dmp-backend/src/main/java/dao/entities/security/UserAuthDaoImpl.java
index 1fb105de3..33f315421 100644
--- a/dmp-backend/src/main/java/dao/entities/security/UserAuthDaoImpl.java
+++ b/dmp-backend/src/main/java/dao/entities/security/UserAuthDaoImpl.java
@@ -22,9 +22,28 @@ public class UserAuthDaoImpl extends JpaDao implements UserAuth
String queryString = "SELECT userAuth.password FROM UserAuth userAuth where userAuth.username = :username";
TypedQuery typedQuery = entityManager.createQuery(queryString, String.class);
typedQuery.setParameter("username", username);
- return typedQuery.getSingleResult();
-
+ try {
+ return typedQuery.getSingleResult();
+ }
+ catch(Exception ex) {
+ return null;
+ }
}
+ @Override
+ public UserAuth getUserAuthBy(String username) {
+
+ String queryString = "FROM UserAuth userAuth where userAuth.username = :username";
+ TypedQuery typedQuery = entityManager.createQuery(queryString, UserAuth.class);
+ typedQuery.setParameter("username", username);
+ try {
+ return typedQuery.getSingleResult();
+ }
+ catch(Exception ex) {
+ return null;
+ }
+ }
+
+
}
diff --git a/dmp-backend/src/main/java/dao/entities/security/UserInfoDao.java b/dmp-backend/src/main/java/dao/entities/security/UserInfoDao.java
index 0922b1fbc..63a17532c 100644
--- a/dmp-backend/src/main/java/dao/entities/security/UserInfoDao.java
+++ b/dmp-backend/src/main/java/dao/entities/security/UserInfoDao.java
@@ -7,6 +7,9 @@ import entities.security.UserInfo;
public interface UserInfoDao extends Dao {
- public UserInfo getByKey(String id, String email);
+ public UserInfo getByIdAndMail(String identification, String email);
+
+ public UserInfo getByAuthenticationId(String authentication);
+
}
\ No newline at end of file
diff --git a/dmp-backend/src/main/java/dao/entities/security/UserInfoDaoImpl.java b/dmp-backend/src/main/java/dao/entities/security/UserInfoDaoImpl.java
index 3f257d8f5..d6d806e60 100644
--- a/dmp-backend/src/main/java/dao/entities/security/UserInfoDaoImpl.java
+++ b/dmp-backend/src/main/java/dao/entities/security/UserInfoDaoImpl.java
@@ -7,6 +7,7 @@ import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import dao.JpaDao;
+import entities.security.UserAuth;
import entities.security.UserInfo;
@@ -20,10 +21,10 @@ public class UserInfoDaoImpl extends JpaDao implements UserInfoD
@Override
- public UserInfo getByKey(String id, String email) {
- String queryString = "FROM UserInfo userInfo where userInfo.id = :userInfoID and userInfo.email = :userInfoEmail";
+ public UserInfo getByIdAndMail(String identification, String email) {
+ String queryString = "FROM UserInfo userInfo where userInfo.identification = :userInfoID and userInfo.email = :userInfoEmail";
TypedQuery typedQuery = entityManager.createQuery(queryString, UserInfo.class);
- typedQuery.setParameter("userInfoID", id);
+ typedQuery.setParameter("userInfoID", identification);
typedQuery.setParameter("userInfoEmail", email);
try {
return typedQuery.getSingleResult();
@@ -32,6 +33,21 @@ public class UserInfoDaoImpl extends JpaDao implements UserInfoD
return null;
}
}
+
+ @Override
+ public UserInfo getByAuthenticationId(String authenticationID) {
+ UserAuth userauth = new UserAuth();
+ userauth.setId(UUID.fromString(authenticationID));
+ String queryString = "FROM UserInfo userInfo where userInfo.authentication = :auth";
+ TypedQuery typedQuery = entityManager.createQuery(queryString, UserInfo.class);
+ typedQuery.setParameter("auth", userauth);
+ try {
+ return typedQuery.getSingleResult();
+ }
+ catch(NoResultException ex) {
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/dmp-backend/src/main/java/rest/entities/Organisations.java b/dmp-backend/src/main/java/rest/entities/Organisations.java
index dfe0a9a65..49b91704e 100644
--- a/dmp-backend/src/main/java/rest/entities/Organisations.java
+++ b/dmp-backend/src/main/java/rest/entities/Organisations.java
@@ -139,7 +139,7 @@ public class Organisations {
org.setId(organisation.getId());
try {
organisationDao.delete(org);
- return ResponseEntity.status(HttpStatus.OK).body("DELETED!");
+ return ResponseEntity.status(HttpStatus.CREATED).body("DELETED!");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"msg\":\"Could not delete organisation!\"");
}
diff --git a/dmp-backend/src/main/java/rest/login/Login.java b/dmp-backend/src/main/java/rest/login/Login.java
index 4db8ae27a..9a6022613 100644
--- a/dmp-backend/src/main/java/rest/login/Login.java
+++ b/dmp-backend/src/main/java/rest/login/Login.java
@@ -1,6 +1,12 @@
package rest.login;
import java.io.Serializable;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@@ -15,9 +21,11 @@ import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-import dao.entities.DataRepositoryDao;
import dao.entities.security.UserAuthDao;
import dao.entities.security.UserInfoDao;
+import entities.security.UserAuth;
+import entities.security.UserInfo;
+import security.TokenSessionManager;
@RestController
@@ -28,19 +36,55 @@ public class Login {
@Autowired private UserInfoDao userInfoDao;
@Autowired private UserAuthDao userAuthDao;
-
- private ObjectMapper objectMapper = new ObjectMapper();
+ @Autowired private TokenSessionManager tokenSessionManager;
- @RequestMapping(method = RequestMethod.POST, value = { "/nativeLogin" }, consumes = "application/json", produces="text/plain")
+
+ @RequestMapping(method = RequestMethod.POST, value = { "/nativeLogin" }, consumes = "application/json", produces = "application/json")
public @ResponseBody ResponseEntity nativeLogin(@RequestBody Credentials credentials) {
+ String token = null;
+
+ if(credentials == null || credentials.getPassword() == null || credentials.getUsername() ==null ||
+ credentials.getPassword().isEmpty() || credentials.getUsername().isEmpty()) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Username and/or password cannot be empty.");
+ }
- System.out.println(userAuthDao.getPasswordHashOfUser("admin"));
+ UserAuth userAuth = userAuthDao.getUserAuthBy(credentials.getUsername());
+ if(userAuth == null) userAuth = new UserAuth();
+ String userHash = userAuth.getPassword();
- return ResponseEntity.status(HttpStatus.OK).body("OUR-GENERATED-TOKEN");
+ String providedHash = "";
+ try {
+ providedHash = tokenSessionManager.hashPassword(credentials.getPassword());
+ }
+ catch(NoSuchAlgorithmException ex) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal error. Cannot authenticate.");
+ }
+
+ if(userHash == null || "".equals(userHash) || !userHash.equals(providedHash)) {
+ return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body("Wrong username or password");
+ }
+ else if(userHash.equals(providedHash)) {
+ // create a token
+ token = tokenSessionManager.generateRandomAlphanumeric(512);
+ // add it to the cache
+ tokenSessionManager.set(credentials.getUsername(), token);
+ }
+
+ //get also the additional info of the user (if he has)
+ UserInfo userInfo = userInfoDao.getByAuthenticationId((userAuth.getId() == null) ? "" : userAuth.getId().toString());
+ if(userInfo == null) userInfo = new UserInfo();
+
+ Response response = new Response();
+ response.setToken(token);
+ response.setEmail(userInfo.getEmail());
+ response.setName(userInfo.getName());
+ response.setUsername(credentials.getUsername());
+
+ return new ResponseEntity(response.toJson(), HttpStatus.OK);
}
@@ -68,3 +112,59 @@ class Credentials implements Serializable{
}
}
+
+class Response implements Serializable {
+
+ private static final long serialVersionUID = -3855159530298902864L;
+
+ private String token;
+ private String username;
+ private String email;
+ private String name;
+
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+
+ public String toJson() {
+ ObjectMapper objMapper = new ObjectMapper();
+ try {
+ return objMapper.writeValueAsString(this);
+ }
+ catch(JsonProcessingException ex) {
+ return "{}";
+ }
+ }
+
+}
+
diff --git a/dmp-backend/src/main/java/security/TokenSessionManager.java b/dmp-backend/src/main/java/security/TokenSessionManager.java
new file mode 100644
index 000000000..18e491f77
--- /dev/null
+++ b/dmp-backend/src/main/java/security/TokenSessionManager.java
@@ -0,0 +1,81 @@
+package security;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.concurrent.TimeUnit;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+public class TokenSessionManager {
+
+ private final static long TOTAL_SESSION_MINUTES = 120L;
+ private final static long IDLE_MINUTES_EXPIRE = 20L;
+
+ private static Cache cache; //that's thread-safe according to the documentation
+
+ private static TokenSessionManager instance = null; //should be one-per-classloader
+
+
+ public static synchronized TokenSessionManager getInstance() {
+ if (instance == null){
+ instance = new TokenSessionManager();
+ initialize();
+ }
+ return instance;
+ }
+
+ private static void initialize() {
+ cache = CacheBuilder.newBuilder()
+ .expireAfterWrite(TOTAL_SESSION_MINUTES, TimeUnit.MINUTES)
+ .expireAfterAccess(IDLE_MINUTES_EXPIRE, TimeUnit.MINUTES)
+ .maximumSize(Long.MAX_VALUE)
+ .build();
+ }
+
+
+ public String get(String key) {
+ return cache.getIfPresent(key);
+ }
+
+ public void set(String key, String value) {
+ cache.put(key, value);
+ }
+
+
+ public String generateRandomAlphanumeric(int length) {
+ SecureRandom random = new SecureRandom();
+ byte bytes[] = new byte[length];
+ random.nextBytes(bytes);
+ return encode(bytes);
+ }
+
+
+ private String encode(byte[] binaryData) {
+ int n = binaryData.length;
+ char[] HEXADECIMAL = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ char[] buffer = new char[n * 2];
+ for (int i = 0; i < n; i++) {
+ int low = (binaryData[i] & 0x0f);
+ int high = ((binaryData[i] & 0xf0) >> 4);
+ buffer[i * 2] = HEXADECIMAL[high];
+ buffer[(i * 2) + 1] = HEXADECIMAL[low];
+ }
+ return new String(buffer);
+ }
+
+
+ public String hashPassword (String password) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(password.getBytes());
+ byte byteData[] = md.digest();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < byteData.length; i++)
+ sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
+ return sb.toString();
+ }
+
+
+
+}
diff --git a/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml b/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml
index a8333cb5b..298b9bcc0 100644
--- a/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml
@@ -25,6 +25,9 @@
+
+
+
diff --git a/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml b/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml
index e51309b46..1110f6bb5 100644
--- a/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml
+++ b/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml
@@ -32,5 +32,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
- -->
+ -->
\ No newline at end of file
diff --git a/dmp-backend/src/main/webapp/WEB-INF/web.xml b/dmp-backend/src/main/webapp/WEB-INF/web.xml
index 11282be42..957c29d88 100644
--- a/dmp-backend/src/main/webapp/WEB-INF/web.xml
+++ b/dmp-backend/src/main/webapp/WEB-INF/web.xml
@@ -1,6 +1,8 @@
+
dmp-backend
+
dmp-backend-rest
org.springframework.web.servlet.DispatcherServlet
@@ -28,6 +30,14 @@
org.springframework.web.context.ContextLoaderListener
+
+
+
+ checks.EnvironmentChecker
+
+
+
+
contextConfigLocation
@@ -51,4 +61,6 @@
-->
+
+
\ No newline at end of file