diff --git a/dmp-backend/pom.xml b/dmp-backend/pom.xml index a81d94abd..799574d81 100644 --- a/dmp-backend/pom.xml +++ b/dmp-backend/pom.xml @@ -7,10 +7,14 @@ 0.0.1-SNAPSHOT war - + 1.19.0 + 1.19.0 + 0.0.1-SNAPSHOT 4.3.8.RELEASE + + 4.2.3.RELEASE 1.19.1 7.0.35 5.2.9.Final @@ -203,6 +207,54 @@ runtime + + + + + + + + + + + + com.google.apis + google-api-services-oauth2 + v2-rev75-1.19.0 + + + com.google.http-client + google-http-client-jackson2 + ${project.http.version} + + + com.google.oauth-client + google-oauth-client-jetty + ${project.oauth.version} + + + + + + + org.springframework.security + spring-security-web + ${org.springframework.security.version} + + + org.springframework.security + spring-security-config + ${org.springframework.security.version} + + + + org.springframework + spring-tx + ${org.springframework.version} + + + + org.apache.commons @@ -211,8 +263,6 @@ - - diff --git a/dmp-backend/src/main/java/exceptions/NonValidTokenException.java b/dmp-backend/src/main/java/exceptions/NonValidTokenException.java new file mode 100644 index 000000000..0d5273f5c --- /dev/null +++ b/dmp-backend/src/main/java/exceptions/NonValidTokenException.java @@ -0,0 +1,11 @@ +package exceptions; + +public class NonValidTokenException extends Exception { + + private static final long serialVersionUID = -2834659827755141154L; + + public NonValidTokenException(String msg) { + super(msg); + } + +} diff --git a/dmp-backend/src/main/java/rest/BackendInterface.java b/dmp-backend/src/main/java/rest/BackendInterface.java index 5cbfa3a69..c31a769d1 100644 --- a/dmp-backend/src/main/java/rest/BackendInterface.java +++ b/dmp-backend/src/main/java/rest/BackendInterface.java @@ -76,6 +76,7 @@ public class BackendInterface { + // FETCH BY DMP(S) @RequestMapping(method = RequestMethod.GET, value = { "/DMP" }, produces="text/plain") diff --git a/dmp-backend/src/main/java/rest/TokenManager.java b/dmp-backend/src/main/java/rest/TokenManager.java new file mode 100644 index 000000000..d302de706 --- /dev/null +++ b/dmp-backend/src/main/java/rest/TokenManager.java @@ -0,0 +1,157 @@ +//package rest; +// +//import java.io.BufferedReader; +//import java.io.IOException; +//import java.io.InputStreamReader; +//import java.io.Serializable; +//import java.io.UnsupportedEncodingException; +//import java.net.HttpURLConnection; +//import java.net.URL; +//import java.security.GeneralSecurityException; +//import java.util.Arrays; +//import java.util.Base64; +//import java.util.Collections; +//import java.util.List; +//import java.util.UUID; +// +//import org.springframework.http.HttpStatus; +//import org.springframework.http.ResponseEntity; +//import org.springframework.web.bind.annotation.CrossOrigin; +//import org.springframework.web.bind.annotation.RequestBody; +//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.ResponseBody; +//import org.springframework.web.bind.annotation.RestController; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +// +//import entities.DMP; +////import io.jsonwebtoken.Claims; +////import io.jsonwebtoken.ExpiredJwtException; +////import io.jsonwebtoken.Jws; +////import io.jsonwebtoken.Jwts; +////import io.jsonwebtoken.MalformedJwtException; +////import io.jsonwebtoken.SignatureException; +////import io.jsonwebtoken.UnsupportedJwtException; +////import security.GoogleKey; +////import security.GoogleKeys; +// +// +//import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; +//import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload; +//import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +//import com.google.api.client.http.HttpTransport; +//import com.google.api.client.http.apache.ApacheHttpTransport; +//import com.google.api.client.http.javanet.NetHttpTransport; +//import com.google.api.client.json.JsonFactory; +//import com.google.api.client.json.jackson2.JacksonFactory; +// +// +// +//@RestController +//@CrossOrigin +//public class TokenManager { +// +// +//// public static final String GOOGLE_KEYS_URL = "https://www.googleapis.com/oauth2/v3/certs"; +//// public static GoogleKeys GOOGLE_KEYS; +// +// private static final JacksonFactory jacksonFactory = new JacksonFactory(); +// private static final HttpTransport transport = new NetHttpTransport(); +// +// private static GoogleIdTokenVerifier verifier; +// +// private static final List clientIDs = Arrays.asList("1010962018903-glegmqudqtl1lub0150vacopbu06lgsg.apps.googleusercontent.com"); +// +// +// +// +// +// +// static { +// verifier = new GoogleIdTokenVerifier.Builder(transport, jacksonFactory) +// .setAudience(clientIDs) +// // Or, if multiple clients access the backend: +// //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3)) +// .build(); +// } +// +// +// +// +// @RequestMapping(method = RequestMethod.POST, value = { "/login" }, produces="text/plain") +// public @ResponseBody ResponseEntity login( +// @RequestParam("token") String token +// ){ +// +// System.out.println(token); +// +// // 1. CHECK IF IT'S A VALID TOKEN +// +// GoogleIdToken idToken = null; +// try { +// idToken = verifier.verify(token); +// } +// catch(GeneralSecurityException ex) { +// return ResponseEntity.status(HttpStatus.FORBIDDEN).body("{'reason': 'Token is not valid'}"); +// } +// catch(IOException ex) { +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{'reason': 'Could not verify token'}"); +// } +// +// +// if (idToken != null) { +// Payload payload = idToken.getPayload(); +// +// System.out.println("============================="); +// // Print user identifier +// String userId = payload.getSubject(); +// System.out.println("User ID: " + userId); +// +// // Get profile information from payload +// String email = payload.getEmail(); +// boolean emailVerified = Boolean.valueOf(payload.getEmailVerified()); +// String name = (String) payload.get("name"); +// String pictureUrl = (String) payload.get("picture"); +// String locale = (String) payload.get("locale"); +// String familyName = (String) payload.get("family_name"); +// String givenName = (String) payload.get("given_name"); +// +// System.out.println(email); +// System.out.println(name); +// System.out.println(familyName); +// System.out.println(locale); +// System.out.println(givenName); +// System.out.println(emailVerified); +// System.out.println(pictureUrl); +// +// +// } else { +// System.out.println("Invalid ID token."); +// } +// +// +// // 2.1 IF SO, ADD USER ON THE DATABASE +// +// // 2.2 also handle it within the session (create a c\\.ustom session) +// +// +// +// return ResponseEntity.status(HttpStatus.OK).body("{'status': 'ok'}"); +// +//// try { +//// List allIDs = dMPDao.listAllIDs(); +//// return ResponseEntity.status(HttpStatus.OK).body(new ObjectMapper().writeValueAsString(allIDs)); +//// } +//// catch(Exception ex) { +//// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Serialization issue: "+ex.getMessage()); +//// } +// +// +// } +// +// +// +//} +// diff --git a/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java b/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java new file mode 100644 index 000000000..9a68d7ed7 --- /dev/null +++ b/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java @@ -0,0 +1,43 @@ +package security; + +import java.util.ArrayList; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.token.Token; +import org.springframework.security.core.token.TokenService; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +@Component +public class CustomAuthenticationProvider implements AuthenticationProvider { + + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + + System.out.println("Running authentication provider's authenticate()"); + + if(authentication == null) { + throw new AuthenticationServiceException("Authentication failed"); + } + + //authentication is ok + return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), new ArrayList<>()); + + + } + + @Override + public boolean supports(Class authentication) { + return authentication.equals(UsernamePasswordAuthenticationToken.class); + } + +} \ No newline at end of file diff --git a/dmp-backend/src/main/java/security/GoogleTokenValidator.java b/dmp-backend/src/main/java/security/GoogleTokenValidator.java new file mode 100644 index 000000000..9d4c5b204 --- /dev/null +++ b/dmp-backend/src/main/java/security/GoogleTokenValidator.java @@ -0,0 +1,77 @@ +package security; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Arrays; +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +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; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; + +import exceptions.NonValidTokenException; +import security.entities.UserInfo; + +public class GoogleTokenValidator { + + private static final JacksonFactory jacksonFactory = new JacksonFactory(); + private static final HttpTransport transport = new NetHttpTransport(); + + private static final List clientIDs = Arrays.asList("1010962018903-glegmqudqtl1lub0150vacopbu06lgsg.apps.googleusercontent.com"); + + private GoogleIdTokenVerifier verifier = null; + + + public GoogleTokenValidator() { + verifier = new GoogleIdTokenVerifier.Builder(transport, jacksonFactory) + .setAudience(clientIDs) + // Or, if multiple clients access the backend: + //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3)) + .build(); + } + + + public UserInfo validateToken(String token) throws NonValidTokenException { + + GoogleIdToken idToken = null; + try { + idToken = verifier.verify(token); + } + catch(GeneralSecurityException ex) { + throw new NonValidTokenException("Token is not valid -> "+ex.getMessage()); + } + catch(IOException ex) { + throw new NonValidTokenException("Could not verify token -> "+ex.getMessage()); + } + catch(IllegalArgumentException ex) { + throw new NonValidTokenException("Could not verify token"); + } + + + if (idToken != null) { + 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; + + } else { + throw new NonValidTokenException("Not a valid token"); + } + } + + + + + +} diff --git a/dmp-backend/src/main/java/security/SecurityConfig.java b/dmp-backend/src/main/java/security/SecurityConfig.java new file mode 100644 index 000000000..65489b787 --- /dev/null +++ b/dmp-backend/src/main/java/security/SecurityConfig.java @@ -0,0 +1,42 @@ +//package security; +// +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.context.annotation.ComponentScan; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +//import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +// +////@Configuration +//@EnableWebSecurity +//public class SecurityConfig extends WebSecurityConfigurerAdapter { +// +// @Autowired +// private CustomAuthenticationProvider authProvider; +// +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// System.out.println("inside SecurityConfig.configure(auth) "); +// +// auth.authenticationProvider(authProvider); +// } +// +// @Override +// protected void configure(HttpSecurity http) throws Exception { +// +// System.out.println("inside SecurityConfig.configure(http) "); +// +// http +// .authorizeRequests() +// .anyRequest() +// .authenticated() +// .and() +// .httpBasic(); +// +// http.addFilterBefore(new TokenAuthenticationFilter(), BasicAuthenticationFilter.class); +// +// } +// +//} diff --git a/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java b/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java new file mode 100644 index 000000000..3634f7cf5 --- /dev/null +++ b/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java @@ -0,0 +1,47 @@ +package security; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +import exceptions.NonValidTokenException; +import security.entities.UserInfo; + +public class TokenAuthenticationFilter extends GenericFilterBean { + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { + + final HttpServletRequest httpRequest = (HttpServletRequest) request; + + System.out.println("in TokenAuthenticationFilter.doFilter"); + + // extract token from header + final String accessToken = httpRequest.getHeader("oauth2-token"); + if (accessToken != null) { + // get and check whether token is valid ( from DB or file wherever you are storing the token) + + GoogleTokenValidator gValidator = new GoogleTokenValidator(); + UserInfo userInfo = null; + + try { + userInfo = gValidator.validateToken(accessToken); + final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userInfo.getEmail(), accessToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + } catch (NonValidTokenException e) { + System.out.println("Could not validate a user by his token! Reason: "+e.getMessage()); + } + } + + chain.doFilter(request, response); + } + +} diff --git a/dmp-backend/src/main/java/security/entities/UserInfo.java b/dmp-backend/src/main/java/security/entities/UserInfo.java new file mode 100644 index 000000000..9cb3a19e5 --- /dev/null +++ b/dmp-backend/src/main/java/security/entities/UserInfo.java @@ -0,0 +1,95 @@ +package security.entities; + +import java.io.Serializable; + +public class UserInfo implements Serializable{ + + private static final long serialVersionUID = 1225151430484658395L; + + //required + String id = null; + String email = null; + //non required (could be left null) + Boolean emailIsVerified = null; + String name = null; + String pictureUrl = null; + String locale = null; + String familyName = null; + String givenName = null; + + + + + public UserInfo(String id, String email, Boolean emailIsVerified, String name, String pictureUrl, String locale, String familyName, String givenName) { + this.id = id; + this.email = email; + this.emailIsVerified = emailIsVerified; + this.name = name; + this.pictureUrl = pictureUrl; + this.locale = locale; + this.familyName = familyName; + this.givenName = givenName; + } + + + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + public boolean isEmailIsVerified() { + return emailIsVerified; + } + public void setEmailIsVerified(boolean emailIsVerified) { + this.emailIsVerified = emailIsVerified; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getPictureUrl() { + return pictureUrl; + } + public void setPictureUrl(String pictureUrl) { + this.pictureUrl = pictureUrl; + } + public String getLocale() { + return locale; + } + public void setLocale(String locale) { + this.locale = locale; + } + public String getFamilyName() { + return familyName; + } + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + public String getGivenName() { + return givenName; + } + public void setGivenName(String givenName) { + this.givenName = givenName; + } + + + + @Override + public String toString() { + return "UserInfo [id=" + id + ", email=" + email + ", emailIsVerified=" + emailIsVerified + ", name=" + name + + ", pictureUrl=" + pictureUrl + ", locale=" + locale + ", familyName=" + familyName + ", givenName=" + + givenName + "]"; + } + + +} diff --git a/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml b/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml index f50459666..a9f365b42 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml +++ b/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml @@ -29,7 +29,15 @@ - + + + + + + + + + diff --git a/dmp-backend/src/main/webapp/WEB-INF/dmp.properties b/dmp-backend/src/main/webapp/WEB-INF/dmp.properties index a904f979d..5fe107785 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/dmp.properties +++ b/dmp-backend/src/main/webapp/WEB-INF/dmp.properties @@ -5,9 +5,9 @@ ##########################Persistence########################################## persistence.jdbc.driver = org.postgresql.Driver -persistence.jdbc.url = jdbc:postgresql://localhost:5432/db -persistence.dbusername = db-user -persistence.dbpassword = db-pass +persistence.jdbc.url = jdbc:postgresql://develdb1.madgik.di.uoa.gr:5432/dmptool +persistence.dbusername = dmptool +persistence.dbpassword = dmpt00lu$r ##########################/Persistence########################################## @@ -42,5 +42,4 @@ persistence.hibernate.connectionpool.c3p0.idle_connection_test_period = 3600 persistence.hibernate.connectionpool.c3p0.test_connection_on_checkin = true persistence.hibernate.connectionpool.c3p0.test_connection_on_checkout = false persistence.hibernate.connectionpool.c3p0.preferred_test_query = select 1 -########################Persistence/Hibernate/Connection pool#################### - +########################Persistence/Hibernate/Connection pool#################### \ No newline at end of file diff --git a/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml b/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml new file mode 100644 index 000000000..28e58abf8 --- /dev/null +++ b/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 f900b4a52..0c3aa66c5 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/web.xml +++ b/dmp-backend/src/main/webapp/WEB-INF/web.xml @@ -31,11 +31,24 @@ contextConfigLocation - - /WEB-INF/applicationContext.xml - + /WEB-INF/applicationContext.xml,/WEB-INF/spring-security.xml + 30 + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + springSecurityFilterChain + /* + + + + + \ No newline at end of file