diff --git a/src/main/java/org/hbp/mip/MIPApplication.java b/src/main/java/org/hbp/mip/MIPApplication.java index 66ebfbc9b8aaae042787046d7b40918f73d7beaf..4814eb9e11f657e89133218e9d21622ad215eaf8 100644 --- a/src/main/java/org/hbp/mip/MIPApplication.java +++ b/src/main/java/org/hbp/mip/MIPApplication.java @@ -5,98 +5,14 @@ package org.hbp.mip; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiParam; -import org.apache.log4j.Logger; -import org.hbp.mip.model.User; -import org.hbp.mip.repositories.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -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 javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.security.Principal; @SpringBootApplication -@RestController -@Api(value = "/", description = "MIP API") public class MIPApplication { - private static final Logger LOGGER = Logger.getLogger(MIPApplication.class); - - @Autowired - UserRepository userRepository; - - public static void main(String[] args) { SpringApplication.run(MIPApplication.class, args); } - public String getUserInfos() { - OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication(); - Authentication userAuthentication = oAuth2Authentication.getUserAuthentication(); - return userAuthentication.getDetails().toString(); - } - - /** - * returns the user for the current session. - * <p> - * the "synchronized" keyword is there to avoid a bug that the transaction is supposed to protect me from. - * To test if your solution to removing it works, do the following: - * - clean DB from scratch - * - restart DB and backend (no session or anything like that) - * - log in using the front end - * - check you have no 500 error in the network logs. - * - * @return - */ - public synchronized User getUser() { - User user = new User(getUserInfos()); - User foundUser = userRepository.findOne(user.getUsername()); - user.setAgreeNDA(foundUser.getAgreeNDA()); - userRepository.save(user); - return user; - } - - @RequestMapping(path = "/user", method = RequestMethod.GET) - public Principal user(Principal principal, HttpServletResponse response) { - ObjectMapper mapper = new ObjectMapper(); - - try { - String userJSON = mapper.writeValueAsString(getUser()); - Cookie cookie = new Cookie("user", URLEncoder.encode(userJSON, "UTF-8")); - cookie.setSecure(true); - cookie.setPath("/"); - response.addCookie(cookie); - } catch (JsonProcessingException | UnsupportedEncodingException e) { - LOGGER.trace(e); - } - return principal; - } - - @RequestMapping(path = "/user", method = RequestMethod.POST) - public ResponseEntity<Void> postUser(@ApiParam(value = "Has the user agreed on the NDA") @RequestParam(value = "agreeNDA", required = true) Boolean agreeNDA) { - String username = getUser().getUsername(); - User user = userRepository.findOne(username); - if (user != null) { - user.setAgreeNDA(agreeNDA); - userRepository.save(user); - } - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - } \ No newline at end of file diff --git a/src/main/java/org/hbp/mip/configuration/SecurityConfiguration.java b/src/main/java/org/hbp/mip/configuration/SecurityConfiguration.java index 0904523d2f218750baaa59f243973d5aeefa26d7..e057c357009e475561f34fe710d3490d6ffeb790 100644 --- a/src/main/java/org/hbp/mip/configuration/SecurityConfiguration.java +++ b/src/main/java/org/hbp/mip/configuration/SecurityConfiguration.java @@ -1,5 +1,12 @@ package org.hbp.mip.configuration; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.apache.log4j.Logger; +import org.hbp.mip.controllers.ArticlesApi; +import org.hbp.mip.model.User; +import org.hbp.mip.repositories.UserRepository; import org.hbp.mip.utils.CORSFilter; import org.hbp.mip.utils.CustomLoginUrlAuthenticationEntryPoint; import org.springframework.beans.factory.annotation.Autowired; @@ -10,8 +17,12 @@ import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.client.OAuth2ClientContext; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; @@ -19,6 +30,7 @@ import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilt import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; +import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.web.access.channel.ChannelProcessingFilter; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; @@ -26,6 +38,10 @@ import org.springframework.security.web.csrf.CsrfFilter; import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; +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 org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.util.WebUtils; @@ -36,6 +52,9 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.Principal; /** * Created by mirco on 11.07.16. @@ -43,11 +62,17 @@ import java.io.IOException; @Configuration @EnableOAuth2Client +@RestController public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + private static final Logger LOGGER = Logger.getLogger(ArticlesApi.class); + @Autowired OAuth2ClientContext oauth2ClientContext; + @Autowired + UserRepository userRepository; + @Value("#{'${hbp.client.pre-established-redirect-uri:/login/hbp}'}") String loginUrl; @@ -63,7 +88,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class); http.antMatcher("/**") .authorizeRequests() - .antMatchers("/", "/frontend/**", "/webjars/**", "/v2/api-docs", "/**").permitAll() + .antMatchers("/", "/frontend/**", "/webjars/**", "/v2/api-docs").permitAll() .anyRequest().authenticated() .and().exceptionHandling().authenticationEntryPoint(new CustomLoginUrlAuthenticationEntryPoint(loginUrl)) .and().logout().logoutSuccessUrl(loginUrl).permitAll() @@ -129,4 +154,56 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { return repository; } + public String getUserInfos() { + OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication(); + Authentication userAuthentication = oAuth2Authentication.getUserAuthentication(); + return userAuthentication.getDetails().toString(); + } + + /** + * returns the user for the current session. + * <p> + * the "synchronized" keyword is there to avoid a bug that the transaction is supposed to protect me from. + * To test if your solution to removing it works, do the following: + * - clean DB from scratch + * - restart DB and backend (no session or anything like that) + * - log in using the front end + * - check you have no 500 error in the network logs. + * + * @return + */ + public synchronized User getUser() { + User user = new User(getUserInfos()); + user.setAgreeNDA(user.getAgreeNDA()); + userRepository.save(user); + return user; + } + + @RequestMapping(path = "/user", method = RequestMethod.GET) + public Principal user(Principal principal, HttpServletResponse response) { + ObjectMapper mapper = new ObjectMapper(); + + try { + String userJSON = mapper.writeValueAsString(getUser()); + Cookie cookie = new Cookie("user", URLEncoder.encode(userJSON, "UTF-8")); + cookie.setSecure(true); + cookie.setPath("/"); + response.addCookie(cookie); + } catch (JsonProcessingException | UnsupportedEncodingException e) { + LOGGER.trace(e); + } + return principal; + } + + @RequestMapping(path = "/user", method = RequestMethod.POST) + public ResponseEntity<Void> postUser(@ApiParam(value = "Has the user agreed on the NDA") @RequestParam(value = "agreeNDA", required = true) Boolean agreeNDA) { + String username = getUser().getUsername(); + User user = userRepository.findOne(username); + if (user != null) { + user.setAgreeNDA(agreeNDA); + userRepository.save(user); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + } diff --git a/src/main/java/org/hbp/mip/controllers/AppsApi.java b/src/main/java/org/hbp/mip/controllers/AppsApi.java index cdfafeb6191a12bf37714bc7fac78d24d344996a..70bc3f037609d1e056f9c451449a22324dd8ffbe 100644 --- a/src/main/java/org/hbp/mip/controllers/AppsApi.java +++ b/src/main/java/org/hbp/mip/controllers/AppsApi.java @@ -6,7 +6,7 @@ package org.hbp.mip.controllers; import io.swagger.annotations.*; import org.apache.log4j.Logger; -import org.hbp.mip.MIPApplication; +import org.hbp.mip.configuration.SecurityConfiguration; import org.hbp.mip.model.App; import org.hbp.mip.model.User; import org.hbp.mip.model.Vote; @@ -30,7 +30,7 @@ public class AppsApi { private static final Logger LOGGER = Logger.getLogger(AppsApi.class); @Autowired - MIPApplication mipApplication; + SecurityConfiguration securityConfiguration; @Autowired AppRepository appRepository; @@ -54,7 +54,7 @@ public class AppsApi { @ApiParam(value = "value", required = true) @PathVariable("value") Integer value ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); App app = appRepository.findOne(id); Vote vote = voteRepository.findByUserAndApp(user, app).iterator().next(); diff --git a/src/main/java/org/hbp/mip/controllers/ArticlesApi.java b/src/main/java/org/hbp/mip/controllers/ArticlesApi.java index 7b32a282167a8e6908d3c6d3094ad90a6b217167..cc8cd14d27a3ed1aa9f786c48f59db59d5004e1b 100644 --- a/src/main/java/org/hbp/mip/controllers/ArticlesApi.java +++ b/src/main/java/org/hbp/mip/controllers/ArticlesApi.java @@ -8,7 +8,7 @@ package org.hbp.mip.controllers; import com.github.slugify.Slugify; import io.swagger.annotations.*; import org.apache.log4j.Logger; -import org.hbp.mip.MIPApplication; +import org.hbp.mip.configuration.SecurityConfiguration; import org.hbp.mip.model.Article; import org.hbp.mip.model.User; import org.hbp.mip.repositories.ArticleRepository; @@ -32,7 +32,7 @@ public class ArticlesApi { private static final Logger LOGGER = Logger.getLogger(ArticlesApi.class); @Autowired - MIPApplication mipApplication; + SecurityConfiguration securityConfiguration; @Autowired ArticleRepository articleRepository; @@ -46,7 +46,7 @@ public class ArticlesApi { @ApiParam(value = "Only ask articles from own team") @RequestParam(value = "team", required = false) Boolean team ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); Iterable<Article> articles; if(own != null && own) @@ -81,7 +81,7 @@ public class ArticlesApi { @RequestBody @ApiParam(value = "Article to create", required = true) @Valid Article article ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); article.setCreatedAt(new Date()); if ("published".equals(article.getStatus())) { @@ -140,7 +140,7 @@ public class ArticlesApi { @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); Article article; article = articleRepository.findOne(slug); if (!"published".equals(article.getStatus()) && !article.getCreatedBy().getUsername().equals(user.getUsername())) @@ -159,7 +159,7 @@ public class ArticlesApi { @RequestBody @ApiParam(value = "Article to update", required = true) @Valid Article article ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); String author = articleRepository.findOne(slug).getCreatedBy().getUsername(); diff --git a/src/main/java/org/hbp/mip/controllers/ExperimentApi.java b/src/main/java/org/hbp/mip/controllers/ExperimentApi.java index 558b7edaa658f12877228717b33201356c1d101c..38db3550780e4e1906f1d8959f733be7a9b6878f 100644 --- a/src/main/java/org/hbp/mip/controllers/ExperimentApi.java +++ b/src/main/java/org/hbp/mip/controllers/ExperimentApi.java @@ -4,7 +4,7 @@ import com.google.common.collect.Iterables; import com.google.gson.*; import io.swagger.annotations.*; import org.apache.log4j.Logger; -import org.hbp.mip.MIPApplication; +import org.hbp.mip.configuration.SecurityConfiguration; import org.hbp.mip.model.Experiment; import org.hbp.mip.model.User; import org.hbp.mip.repositories.ExperimentRepository; @@ -58,7 +58,7 @@ public class ExperimentApi { private String miningExaremeQueryUrl; @Autowired - MIPApplication mipApplication; + SecurityConfiguration securityConfiguration; @Autowired ModelRepository modelRepository; @@ -75,7 +75,7 @@ public class ExperimentApi { Experiment experiment = new Experiment(); experiment.setUuid(UUID.randomUUID()); - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); experiment.setAlgorithms(incomingQuery.get("algorithms").toString()); experiment.setValidations(incomingQuery.get("validations").toString()); @@ -127,7 +127,7 @@ public class ExperimentApi { Experiment experiment; UUID experimentUuid; - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); try { experimentUuid = UUID.fromString(uuid); } catch (IllegalArgumentException iae) { @@ -211,7 +211,7 @@ public class ExperimentApi { int maxResultCount, String modelSlug ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); Iterable<Experiment> experiments = null; Iterable<Experiment> myExperiments = experimentRepository.findByCreatedBy(user); @@ -242,7 +242,7 @@ public class ExperimentApi { private ResponseEntity<String> doMarkExperimentAsShared(String uuid, boolean shared) { Experiment experiment; UUID experimentUuid; - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); try { experimentUuid = UUID.fromString(uuid); } catch (IllegalArgumentException iae) { diff --git a/src/main/java/org/hbp/mip/controllers/ModelsApi.java b/src/main/java/org/hbp/mip/controllers/ModelsApi.java index 8e8d37b9f5dd207dadf7d6ea11d458646bb8db86..7d31f7e81a0a4ab732da0e377eb3c746e0ed5c6c 100644 --- a/src/main/java/org/hbp/mip/controllers/ModelsApi.java +++ b/src/main/java/org/hbp/mip/controllers/ModelsApi.java @@ -7,7 +7,7 @@ package org.hbp.mip.controllers; import com.github.slugify.Slugify; import io.swagger.annotations.*; import org.apache.log4j.Logger; -import org.hbp.mip.MIPApplication; +import org.hbp.mip.configuration.SecurityConfiguration; import org.hbp.mip.model.*; import org.hbp.mip.repositories.DatasetRepository; import org.hbp.mip.repositories.ModelRepository; @@ -32,7 +32,7 @@ public class ModelsApi { private static final Logger LOGGER = Logger.getLogger(ModelsApi.class); @Autowired - MIPApplication mipApplication; + SecurityConfiguration securityConfiguration; @Autowired CSVUtil csvUtil; @@ -58,7 +58,7 @@ public class ModelsApi { @ApiParam(value = "Only ask published models") @RequestParam(value = "valid", required = false) Boolean valid ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); Iterable<Model> models = null; if(own != null && own) @@ -98,7 +98,7 @@ public class ModelsApi { @RequestBody @ApiParam(value = "Model to create", required = true) Model model ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); model.setTitle(model.getConfig().getTitle().get("text")); model.setCreatedBy(user); @@ -165,7 +165,7 @@ public class ModelsApi { @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug ) { - User user = mipApplication.getUser(); + User user = securityConfiguration.getUser(); Model model = null;