diff --git a/build.sh b/build.sh index 6a18d98ecec05885651675049490ca44c990ec7f..458b5c085e3c6e51fd26278722210b3d2e8b6617 100755 --- a/build.sh +++ b/build.sh @@ -26,7 +26,7 @@ else DOCKER="sudo docker" fi -IMAGE="kfilippopolitis/portal-backend" +IMAGE="thanasulas/portal-backend" VCS_REF=$(git describe --tags --dirty) VERSION=$(git describe --tags --dirty) diff --git a/docker/README.md b/docker/README.md index cc8c59fe1d79a1a50fcfd566c439cc9d8c5c90e4..da8299413287a703b38d12c233e8abb0c32babfa 100644 --- a/docker/README.md +++ b/docker/README.md @@ -33,7 +33,7 @@ To use this image, you need a running instance of PostgreSQL and to configure th * CLIENT_SECRET: required when authentication is turned on, client secret for the [OpenID server of HBP](https://services.humanbrainproject.eu/oidc/). * TOKEN_URI: default to "https://services.humanbrainproject.eu/oidc/token". * AUTH_URI: default to "https://services.humanbrainproject.eu/oidc/authorize". -* USER_INFO_URI: default to "https://services.humanbrainproject.eu/oidc/userinfo". +* USER_INFO_URI: default to "https://services.humanbrainproject.eu/oidc/userInfo". * REVOKE_TOKEN_URI "https://services.humanbrainproject.eu/oidc/slo". diff --git a/docker/config/application.tmpl b/docker/config/application.tmpl index f2587889371ac5ddd7f6bbad5b2f5574d303e07e..257bfa0871747ff23d288c5cdf53be4086ce2827 100644 --- a/docker/config/application.tmpl +++ b/docker/config/application.tmpl @@ -1,14 +1,13 @@ # Configuration template for the portal running inside a Docker container -# See http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +### DATABASE CONFIGURATION ### spring: portal-datasource: - url: {{ default .Env.PORTAL_DB_URL "jdbc:postgresql://172.22.0.1:5432/portal" }} + url: {{ default .Env.PORTAL_DB_URL "jdbc:postgresql://88.197.53.106:5432/portal" }} schema: {{ default .Env.PORTAL_DB_SCHEMA "public" }} username: {{ default .Env.PORTAL_DB_USER "postgres" }} password: {{ .Env.PORTAL_DB_PASSWORD }} driver-class-name: org.postgresql.Driver - data: jpa: repositories: @@ -18,26 +17,7 @@ spring: dialect: org.hibernate.dialect.PostgreSQL9Dialect ddl-auto: validate - # SPRING RESOURCES HANDLING - resources: - chain: - enabled: true # TODO: why is that enabled? Do we serve any resources from the backend? - -# HBP OAUTH2 LOGIN -hbp: - authentication: - enabled: {{ default .Env.AUTHENTICATION "1" }} - client: - clientId: {{ default .Env.CLIENT_ID "996f97c5-a3ca-460e-b18b-00df3e2be89a" }} - clientSecret: {{ .Env.CLIENT_SECRET }} - logoutUri: {{ .Env.LOGOUT_URI }} - -# WEB FRONTEND -frontend: - loginUrl: {{ default .Env.FRONTEND_LOGIN_URL "http://frontend/services/login/hbp" }} - redirectAfterLoginUrl: {{ default .Env.FRONTEND_AFTER_LOGIN_URL "http://frontend/" }} - redirectAfterLogoutUrl: {{ default .Env.FRONTEND_AFTER_LOGOUT_URL (default .Env.LOGIN_URI "http://frontend/services/login/hbp") }} - +### LOG LEVELS ### logging: level: root: {{ default .Env.LOG_LEVEL_FRAMEWORK "ERROR" }} @@ -45,16 +25,14 @@ logging: eu: hbp: {{ default .Env.LOG_LEVEL "INFO" }} -# EMBEDDED SERVER CONFIGURATION +### EMBEDDED SERVER CONFIGURATION ### server: servlet: - contextPath: {{ default .Env.CONTEXT_PATH "/services" }} + contextPath: "/services" port: 8080 - use-forward-headers: true - session: - timeout: {{ default .Env.SESSION_TIMEOUT "2592000" }} + forward-headers-strategy: native -# ENDPOINTS +### ENDPOINTS ### endpoints: enabled: true health: @@ -62,6 +40,7 @@ endpoints: endpoint: /health sensitive: false +### EXTERNAL SERVICES ### services: exareme: queryExaremeUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/query @@ -74,11 +53,23 @@ services: galaxyUsername: {{ default .Env.GALAXY_USERNAME "admin" }} galaxyPassword: {{ default .Env.GALAXY_PASSWORD "password" }} - keycloak: - keycloakUrl: {{ .Env.KEYCLOAK_URL }} +### Authentication ### +authentication: + enabled: {{ default .Env.AUTHENTICATION "1" }} -pathologies: - pathologiesUrl: "file:/opt/portal/api/pathologies.json" +### Keycloak ### +keycloak: + enabled: true + auth-server-url: {{ .Env.KEYCLOAK_AUTH_URL }} + realm: {{ .Env.KEYCLOAK_REALM }} + resource: {{ .Env.CLIENT_ID }} + enable-basic-auth: true + credentials: + secret: {{ .Env.CLIENT_SECRET }} + principal-attribute: "preferred_username" -algorithms: - disabledAlgorithmsUrl: "file:/opt/portal/api/disabledAlgorithms.json" \ No newline at end of file +### EXTERNAL FILES ### +# Files are imported when building the docker image +files: + pathologies_json: "file:/opt/portal/api/pathologies.json" + disabledAlgorithms_json: "file:/opt/portal/api/disabledAlgorithms.json" diff --git a/pom.xml b/pom.xml index 97d528b788f61fa50b570ece91b38ade11cfc6d9..60a5d582c47501154054ba3bc8e41927cdbb2922 100644 --- a/pom.xml +++ b/pom.xml @@ -18,11 +18,9 @@ </parent> <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <sonar.host.url>https://hbps1.chuv.ch/sonarqube/</sonar.host.url> - <sonar.projectName>MIP portal-backend</sonar.projectName> - <sonar.sources>src/main/java/</sonar.sources> <java.version>1.8</java.version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <keycloak-spring.version>11.0.2</keycloak-spring.version> <springfox-swagger.version>2.5.0</springfox-swagger.version> <spring-context.version>5.2.10.RELEASE</spring-context.version> <springfox-boot-starter.version>3.0.0</springfox-boot-starter.version> @@ -46,6 +44,7 @@ <flyway-core.version>4.2.0</flyway-core.version> <hibernate-jpa-2.1-api.version>1.0.0.Final</hibernate-jpa-2.1-api.version> <hibernate.version>5.4.10.Final</hibernate.version> + <hibernate-validator.version>6.1.0.Final</hibernate-validator.version> <aspectjweaver.version>1.8.9</aspectjweaver.version> <javax-inject.version>1</javax-inject.version> <protobuf-java.version>3.1.0</protobuf-java.version> @@ -73,7 +72,7 @@ </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> + <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> @@ -81,30 +80,21 @@ </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.security.oauth.boot</groupId> - <artifactId>spring-security-oauth2-autoconfigure</artifactId> - <version>2.0.1.RELEASE</version> - </dependency> - <dependency> - <groupId>org.springframework.security</groupId> - <artifactId>spring-security-oauth2-resource-server</artifactId> + <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> - <groupId>org.springframework.security.oauth</groupId> - <artifactId>spring-security-oauth2</artifactId> - <version>2.5.0.RELEASE</version> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-commons</artifactId> </dependency> <dependency> - <groupId>net.logstash.logback</groupId> - <artifactId>logstash-logback-encoder</artifactId> - <version>6.4</version> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-spring-boot-starter</artifactId> + <version>${keycloak-spring.version}</version> </dependency> <dependency> - <groupId>org.springframework.data</groupId> - <artifactId>spring-data-commons</artifactId> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-spring-security-adapter</artifactId> + <version>${keycloak-spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> @@ -145,6 +135,11 @@ <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-validator</artifactId> + <version>${hibernate-validator.version}</version> + </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> @@ -257,11 +252,11 @@ <artifactId>svenson</artifactId> <version>1.5.8</version> </dependency> - <!--<dependency> + <dependency> <groupId>eu.hbp.mip</groupId> <artifactId>portal-backend</artifactId> <version>4.0.0</version> - </dependency>--> + </dependency> </dependencies> <build> @@ -275,11 +270,12 @@ <include>**/*.csv</include> <include>**/*.sql</include> <include>**/*.conf</include> - <!-- <include>**/*.yml</include> Only for development --> + <include>**/*.yml</include> <!-- Only for development --> </includes> <filtering>true</filtering> - </resource> + + <!-- Used for development. Docker/config folder files added as resources --> <resource> <directory>config</directory> <includes> diff --git a/src/main/java/eu/hbp/mip/MIPApplication.java b/src/main/java/eu/hbp/mip/MIPApplication.java index 9af69bdd9cdc04e555a24f8a0ca4e7b3882206ed..f4001f93c477307cf0d464f76e8b22b2905af198 100644 --- a/src/main/java/eu/hbp/mip/MIPApplication.java +++ b/src/main/java/eu/hbp/mip/MIPApplication.java @@ -7,17 +7,12 @@ package eu.hbp.mip; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @SpringBootApplication public class MIPApplication { - private static final Logger LOGGER = LoggerFactory.getLogger(MIPApplication.class); - public static void main(String[] args) { SpringApplication.run(MIPApplication.class, args); } - } diff --git a/src/main/java/eu/hbp/mip/configuration/CacheConfiguration.java b/src/main/java/eu/hbp/mip/configuration/CacheConfiguration.java deleted file mode 100644 index b7300fc257fcef4afd29421d8ccef64aeb0a11dd..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/configuration/CacheConfiguration.java +++ /dev/null @@ -1,13 +0,0 @@ -package eu.hbp.mip.configuration; - -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Configuration; - -/** - * Created by mirco on 07.11.16. - */ - -@Configuration -@EnableCaching -public class CacheConfiguration { -} diff --git a/src/main/java/eu/hbp/mip/configuration/SecurityConfiguration.java b/src/main/java/eu/hbp/mip/configuration/SecurityConfiguration.java deleted file mode 100644 index 81afa6418383a2a9817bdf0770f4a0b90a08af25..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/configuration/SecurityConfiguration.java +++ /dev/null @@ -1,297 +0,0 @@ -package eu.hbp.mip.configuration; - -import eu.hbp.mip.utils.CORSFilter; -import eu.hbp.mip.utils.CustomAccessDeniedHandler; -import eu.hbp.mip.utils.CustomLoginUrlAuthenticationEntryPoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor; -import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; -import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.oauth2.client.OAuth2ClientContext; -import org.springframework.security.oauth2.client.OAuth2RestTemplate; -import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; -import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; -import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails; -import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; -import org.springframework.security.web.access.channel.ChannelProcessingFilter; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.security.web.authentication.logout.LogoutHandler; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -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.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.filter.OncePerRequestFilter; -import org.springframework.web.util.WebUtils; - -import javax.net.ssl.*; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.URI; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - - -// Reference for OAuth2 login: https://spring.io/guides/tutorials/spring-boot-oauth2/ -// also http://cscarioni.blogspot.ch/2013/04/pro-spring-security-and-oauth-2.html -// Security with Keycloak: https://www.thomasvitale.com/keycloak-authentication-flow-sso-client/ - -@Configuration -@EnableOAuth2Client -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfiguration.class); - - @Qualifier("oauth2ClientContext") - @Autowired - private OAuth2ClientContext oauth2ClientContext; - - /** - * Enable HBP collab authentication (1) or disable it (0). Default is 1 - */ - @Value("#{'${hbp.authentication.enabled}'}") - private boolean authenticationEnabled; - - /** - * Absolute URL to redirect to when login is required - */ - @Value("#{'${frontend.loginUrl}'}") - private String loginUrl; - - /** - * Absolute URL to redirect to when logout is required - */ - @Value("#{'${hbp.client.logoutUri}'}") - private String logoutUrl; - - /** - * Absolute URL to redirect to after successful login - */ - @Value("#{'${frontend.redirectAfterLoginUrl}'}") - private String frontendRedirectAfterLogin; - - /** - * Absolute URL to redirect to after successful logout - */ - @Value("#{'${frontend.redirectAfterLogoutUrl}'}") - private String redirectAfterLogoutUrl; - - public boolean getAuthenticationEnabled() { - return authenticationEnabled; - } - - public String getFrontendRedirectAfterLogin() { - return frontendRedirectAfterLogin; - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - disableCertificateValidation(); - // @formatter:off - http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class); - - if (authenticationEnabled) { - http.antMatcher("/**") - .authorizeRequests() - .antMatchers( - "/", "/login/**", "/health/**", "/info/**", "/metrics/**", - "/trace/**", "/frontend/**", "/webjars/**", "/v2/api-docs", - "/swagger-ui.html", "/swagger-resources/**" - ).permitAll() - .antMatchers("/galaxy*", "/galaxy/*").hasRole("Data Manager") - .anyRequest().hasRole("Researcher") - .and().exceptionHandling().authenticationEntryPoint(new CustomLoginUrlAuthenticationEntryPoint(loginUrl)) - .accessDeniedHandler(new CustomAccessDeniedHandler()) - .and().logout().addLogoutHandler(authLogoutHandler()).logoutSuccessUrl(redirectAfterLogoutUrl) - .and().logout().permitAll() - .and().csrf().ignoringAntMatchers("/logout").csrfTokenRepository(csrfTokenRepository()) - .and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class) - .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class); - } else { - http.antMatcher("/**") - .authorizeRequests() - .antMatchers("/**").permitAll() - .and().csrf().disable(); - } - } - - private Filter ssoFilter() { - OAuth2ClientAuthenticationProcessingFilter hbpFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/hbp"); - OAuth2RestTemplate hbpTemplate = new OAuth2RestTemplate(hbp(), oauth2ClientContext); - hbpFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler(frontendRedirectAfterLogin)); - hbpFilter.setRestTemplate(hbpTemplate); - hbpFilter.setTokenServices(new UserInfoTokenServices(hbpResource().getUserInfoUri(), hbp().getClientId())); - return hbpFilter; - } - - @Bean - public FilterRegistrationBean oauth2ClientFilterRegistration( - OAuth2ClientContextFilter filter) { - FilterRegistrationBean registration = new FilterRegistrationBean(); - registration.setFilter(filter); - registration.setOrder(-100); - return registration; - } - - @Bean(name = "hbp") - @ConfigurationProperties("hbp.client") - public BaseOAuth2ProtectedResourceDetails hbp() { - return new AuthorizationCodeResourceDetails(); - } - - @Bean(name = "hbpResource") - @ConfigurationProperties("hbp.resource") - public ResourceServerProperties hbpResource() { - return new ResourceServerProperties(); - } - - - private Filter csrfHeaderFilter() { - return new OncePerRequestFilter() { - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); - if (csrf != null) { - Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); - String token = csrf.getToken(); - if (cookie == null || token != null && !token.equals(cookie.getValue())) { - cookie = new Cookie("XSRF-TOKEN", token); - cookie.setPath("/"); - response.addCookie(cookie); - } - } - filterChain.doFilter(request, response); - } - }; - } - - private CsrfTokenRepository csrfTokenRepository() { - HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); - repository.setHeaderName("X-XSRF-TOKEN"); - return repository; - } - - @Bean - public AuthoritiesExtractor keycloakAuthoritiesExtractor() { - return new KeycloakAuthoritiesExtractor(); - } - - - public class KeycloakAuthoritiesExtractor - implements AuthoritiesExtractor { - - @Override - public List<GrantedAuthority> extractAuthorities - (Map<String, Object> map) { - return AuthorityUtils - .commaSeparatedStringToAuthorityList(asAuthorities(map)); - } - - private String asAuthorities(Map<String, Object> map) { - List<String> authorities = new ArrayList<>(); -// authorities.add("BAELDUNG_USER"); - List<LinkedHashMap<String, String>> authz; - authz = (List<LinkedHashMap<String, String>>) map.get("authorities"); - for (LinkedHashMap<String, String> entry : authz) { - authorities.add(entry.get("authority")); - } - return String.join(",", authorities); - } - } - - - private LogoutHandler authLogoutHandler() { - return (request, response, authentication) -> { - logout(); - }; - } - - - public void logout() { - // TODO Try removing - - RestTemplate restTemplate = new RestTemplate(); - MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>(); - formParams.add("client_id", hbp().getClientId()); - formParams.add("client_secret", hbp().getClientSecret()); - formParams.add("refresh_token", this.oauth2ClientContext.getAccessToken().getRefreshToken().getValue()); - - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); - RequestEntity<MultiValueMap<String, String>> requestEntity = - new RequestEntity<>(formParams, httpHeaders, HttpMethod.POST, - URI.create(logoutUrl)); - restTemplate.exchange(requestEntity, String.class); - } - - @Value("#{'${services.keycloak.keycloakUrl}'}") - private String keycloakUrl; - - public void disableCertificateValidation() { - - //TODO Refactor logging - - LOGGER.info("disabling certificate validation host : " + keycloakUrl); - - // Create a trust manager that does not validate certificate chains - TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - - public void checkClientTrusted(X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted(X509Certificate[] certs, String authType) { - } - }}; - - - // Ignore differences between given hostname and certificate hostname - HostnameVerifier hv = - (hostname, session) -> hostname.equals(keycloakUrl) && session.getPeerHost().equals(keycloakUrl); - - // Install the all-trusting trust manager - try { - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, new SecureRandom()); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - HttpsURLConnection.setDefaultHostnameVerifier(hv); - } catch (Exception e) { - // TODO add log message - } - - } - -} diff --git a/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java b/src/main/java/eu/hbp/mip/configurations/APIMetadataConfiguration.java similarity index 69% rename from src/main/java/eu/hbp/mip/configuration/WebConfiguration.java rename to src/main/java/eu/hbp/mip/configurations/APIMetadataConfiguration.java index 72bcad78905f685bc15b11ca493f255db577f071..7b9eab4563d9c71af0a0eac7d6bae42d798df93b 100644 --- a/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java +++ b/src/main/java/eu/hbp/mip/configurations/APIMetadataConfiguration.java @@ -1,4 +1,4 @@ -package eu.hbp.mip.configuration; +package eu.hbp.mip.configurations; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,18 +10,9 @@ import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; -/** - * Created by mirco on 11.07.16. - */ - @Configuration @EnableSwagger2 -public class WebConfiguration { - -// @Bean -// public String[] swaggerUiConfig() { -// return UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS; -// } +public class APIMetadataConfiguration { @Bean public Docket swaggerDocumentation() { @@ -36,10 +27,8 @@ public class WebConfiguration { private ApiInfo metadata() { return new ApiInfoBuilder() .title("Medical Informatics Platform API") - .description("Serve the MIP Frontend") - .version("1.0") - .contact(new Contact("Mirco Nasuti", "https://www.unil.ch/lren/en/home.html", "mirco.nasuti@chuv.ch")) + .description("Serving the MIP Frontend") + .contact(new Contact("Kostas Filippopolitis", "https://github.com/KFilippopolitis", "kostasfilippop@gmail.com")) .build(); } - } diff --git a/src/main/java/eu/hbp/mip/configurations/GalaxyAuthentication.java b/src/main/java/eu/hbp/mip/configurations/GalaxyAuthentication.java new file mode 100644 index 0000000000000000000000000000000000000000..41888d3ea276138e425e790cde46867f8ce3e31b --- /dev/null +++ b/src/main/java/eu/hbp/mip/configurations/GalaxyAuthentication.java @@ -0,0 +1,51 @@ +package eu.hbp.mip.configurations; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import eu.hbp.mip.services.ActiveUserService; +import eu.hbp.mip.utils.Logging; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Base64; + +@RestController +public class GalaxyAuthentication { + + @Autowired + private ActiveUserService activeUserService; + + @Value("#{'${services.galaxy.galaxyUsername:admin}'}") + private String galaxyUsername; + + @Value("#{'${services.galaxy.galaxyPassword:password}'}") + private String galaxyPassword; + + @Value("#{'${services.galaxy.galaxpathoyContext:nativeGalaxy}'}") + private String galaxyContext; + + /** + * Get Galaxy Reverse Proxy basic access token. + * + * @return Return a @{@link ResponseEntity} with the token. + */ + @RequestMapping(path = "/galaxy", method = RequestMethod.GET, produces = "application/json") + @PreAuthorize("hasRole('Data Manager')") + @ResponseStatus(value = HttpStatus.OK) + public ResponseEntity getGalaxyConfiguration() { + String stringEncoded = Base64.getEncoder().encodeToString((galaxyUsername + ":" + galaxyPassword).getBytes()); + JsonObject object = new JsonObject(); + object.addProperty("authorization", stringEncoded); + object.addProperty("context", galaxyContext); + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), "(GET) /user/galaxy", "Successfully Loaded galaxy information."); + + return ResponseEntity.ok(new Gson().toJson(object)); + } +} diff --git a/src/main/java/eu/hbp/mip/configuration/PersistenceConfiguration.java b/src/main/java/eu/hbp/mip/configurations/PersistenceConfiguration.java similarity index 94% rename from src/main/java/eu/hbp/mip/configuration/PersistenceConfiguration.java rename to src/main/java/eu/hbp/mip/configurations/PersistenceConfiguration.java index 909d2c1c81dc040c78bba7c29d4f43bcb1e925ca..181bc639c05ea4b3987459cf36a62664db6812cb 100644 --- a/src/main/java/eu/hbp/mip/configuration/PersistenceConfiguration.java +++ b/src/main/java/eu/hbp/mip/configurations/PersistenceConfiguration.java @@ -1,4 +1,4 @@ -package eu.hbp.mip.configuration; +package eu.hbp.mip.configurations; import org.flywaydb.core.Flyway; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -36,7 +36,7 @@ public class PersistenceConfiguration { emfb.setDataSource(portalDataSource()); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); emfb.setJpaVendorAdapter(vendorAdapter); - emfb.setPackagesToScan("eu.hbp.mip.model.DAOs"); + emfb.setPackagesToScan("eu.hbp.mip.models.DAOs"); return emfb; } diff --git a/src/main/java/eu/hbp/mip/configurations/SecurityConfiguration.java b/src/main/java/eu/hbp/mip/configurations/SecurityConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..dfc5d4e475634dfc3bf8754bb3ea6584953313c7 --- /dev/null +++ b/src/main/java/eu/hbp/mip/configurations/SecurityConfiguration.java @@ -0,0 +1,83 @@ +package eu.hbp.mip.configurations; + +import org.keycloak.adapters.KeycloakConfigResolver; +import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; +import org.keycloak.adapters.springsecurity.KeycloakConfiguration; +import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; +import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; +import org.springframework.security.core.session.SessionRegistryImpl; +import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + + +@Controller +@KeycloakConfiguration +public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter { + + // Redirect to login page url + private static final String logoutRedirectURL = "/sso/login"; + + @Value("#{'${authentication.enabled}'}") + private boolean authenticationEnabled; + + @Override + protected void configure(HttpSecurity http) throws Exception { + super.configure(http); + + if (authenticationEnabled) { + http.authorizeRequests() + .antMatchers( + "/sso/login", + "/v2/api-docs", "/swagger-ui/**", "/swagger-resources/**" // Swagger URLs + ).permitAll() + .antMatchers("/galaxy*", "/galaxy/*").hasRole("DATA MANAGER") + .anyRequest().hasRole("RESEARCHER"); + } else { + http.antMatcher("/**") + .authorizeRequests() + .antMatchers("/**").permitAll() + .and().csrf().disable(); + } + } + + @Autowired + private HttpServletRequest request; + + @GetMapping(value = "/logout") + public String logout() throws ServletException { + request.logout(); + return String.format("redirect:%s", logoutRedirectURL); + } + + @Bean + public KeycloakConfigResolver KeycloakConfigResolver() { + return new KeycloakSpringBootConfigResolver(); + } + + @Override + protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { + return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper(); + grantedAuthorityMapper.setConvertToUpperCase(true); + + KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); + keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper); + auth.authenticationProvider(keycloakAuthenticationProvider); + } + +} diff --git a/src/main/java/eu/hbp/mip/controllers/ActiveUserAPI.java b/src/main/java/eu/hbp/mip/controllers/ActiveUserAPI.java new file mode 100644 index 0000000000000000000000000000000000000000..7e5209b75b5ec2e112dd56c6a4ee8ef778221e39 --- /dev/null +++ b/src/main/java/eu/hbp/mip/controllers/ActiveUserAPI.java @@ -0,0 +1,44 @@ +package eu.hbp.mip.controllers; + +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.services.ActiveUserService; +import eu.hbp.mip.utils.Logging; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +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.RestController; + +import javax.servlet.http.HttpServletResponse; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@RestController +@RequestMapping(value = "/activeUser", produces = {APPLICATION_JSON_VALUE}) +@Api(value = "/activeUser") +public class ActiveUserAPI { + + @Autowired + private ActiveUserService activeUserService; + + @ApiOperation(value = "Get the active user", response = UserDAO.class) + @RequestMapping(method = RequestMethod.GET) + public ResponseEntity<UserDAO> getTheActiveUser(HttpServletResponse response) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), "(GET) /activeUser", + "Loading the details of the activeUser"); + + return ResponseEntity.ok(activeUserService.getActiveUser()); + } + + @ApiOperation(value = "The active user agrees to the NDA", response = UserDAO.class) + @RequestMapping(value = "/agreeNDA", method = RequestMethod.POST) + public ResponseEntity<UserDAO> activeUserServiceAgreesToNDA(@RequestBody(required = false) UserDAO userDAO) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), "(GET) /activeUser/agreeNDA", + "The user agreed to the NDA"); + + return ResponseEntity.ok(activeUserService.agreeToNDA()); + } +} diff --git a/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java b/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java similarity index 93% rename from src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java rename to src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java index 8fc9fcbf93ffb65ad33dcda8617ebf515e0f306d..001409d25552ff77a12f6df12e79c46c297754c2 100644 --- a/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java +++ b/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java @@ -8,16 +8,15 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; -import eu.hbp.mip.model.DTOs.AlgorithmDTO; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.model.galaxy.WorkflowDTO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; +import eu.hbp.mip.services.ActiveUserService; +import eu.hbp.mip.models.galaxy.WorkflowDTO; import eu.hbp.mip.utils.CustomResourceLoader; import eu.hbp.mip.utils.HTTPUtil; import eu.hbp.mip.utils.Logging; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; @@ -38,13 +37,12 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RestController @RequestMapping(value = "/algorithms", produces = {APPLICATION_JSON_VALUE}) @Api(value = "/algorithms") -public class AlgorithmsApi { +public class AlgorithmsAPI { private static final Gson gson = new Gson(); - @Qualifier("userInfo") @Autowired - private UserInfo userInfo; + private ActiveUserService activeUserService; @Value("#{'${services.exareme.algorithmsUrl}'}") private String exaremeAlgorithmsUrl; @@ -55,13 +53,13 @@ public class AlgorithmsApi { @Value("#{'${services.galaxy.galaxyApiKey}'}") private String galaxyApiKey; - @Value("#{'${services.algorithms.disabledAlgorithmsUrl}'}") - private String disabledAlgorithmsUrl; + @Value("#{'${files.disabledAlgorithms_json}'}") + private String disabledAlgorithmsFilePath; @ApiOperation(value = "List all algorithms", response = String.class) @RequestMapping(method = RequestMethod.GET) public ResponseEntity<List<AlgorithmDTO>> getAlgorithms() { - String username = userInfo.getUser().getUsername(); + String username = activeUserService.getActiveUser().getUsername(); String endpoint = "(GET) /algorithms"; Logging.LogUserAction(username, endpoint, "Executing..."); @@ -110,7 +108,7 @@ public class AlgorithmsApi { * @return a list of AlgorithmDTOs or null if something fails */ public LinkedList<AlgorithmDTO> getExaremeAlgorithms() { - String username = userInfo.getUser().getUsername(); + String username = activeUserService.getActiveUser().getUsername(); String endpoint = "(GET) /algorithms"; LinkedList<AlgorithmDTO> algorithms = new LinkedList<>(); // Get exareme algorithms @@ -139,7 +137,7 @@ public class AlgorithmsApi { * @return a list of AlgorithmDTOs or null if something fails */ public LinkedList<AlgorithmDTO> getGalaxyWorkflows() { - String username = userInfo.getUser().getUsername(); + String username = activeUserService.getActiveUser().getUsername(); String endpoint = "(GET) /algorithms"; List<Workflow> workflowList; try { @@ -150,7 +148,6 @@ public class AlgorithmsApi { workflowList = new ArrayList<>(workflowsClient.getWorkflows()); } catch (Exception e) { Logging.LogUserAction(username, endpoint, "Error when calling list galaxy workflows: " + e.getMessage()); - return null; } @@ -205,7 +202,7 @@ public class AlgorithmsApi { */ List<String> getDisabledAlgorithms() throws IOException { - Resource resource = resourceLoader.getResource(disabledAlgorithmsUrl); + Resource resource = resourceLoader.getResource(disabledAlgorithmsFilePath); List<String> response = gson.fromJson(convertInputStreamToString( resource.getInputStream()), diff --git a/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java similarity index 83% rename from src/main/java/eu/hbp/mip/controllers/ExperimentApi.java rename to src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java index 803c475723eb1a86bdc4f75e5112d67994de981d..78f6032e06beb3aa0607a03553975b2a5c72037c 100644 --- a/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java +++ b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java @@ -1,6 +1,8 @@ package eu.hbp.mip.controllers; -import eu.hbp.mip.model.DTOs.ExperimentDTO; + +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.services.ActiveUserService; import eu.hbp.mip.services.ExperimentService; import eu.hbp.mip.utils.JsonConverters; import io.swagger.annotations.Api; @@ -23,11 +25,11 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RestController @RequestMapping(value = "/experiments", produces = {APPLICATION_JSON_VALUE}) @Api(value = "/experiments") -public class ExperimentApi { +public class ExperimentAPI { private final ExperimentService experimentService; - public ExperimentApi(ExperimentService experimentService) { + public ExperimentAPI(ExperimentService experimentService) { this.experimentService = experimentService; } @@ -38,8 +40,8 @@ public class ExperimentApi { @RequestParam(name = "algorithm", required = false) String algorithm, @RequestParam(name = "shared", required = false) Boolean shared, @RequestParam(name = "viewed", required = false) Boolean viewed, - @RequestParam(name = "orderBy", required = false, defaultValue = "created") String orderBy, - @RequestParam(name = "descending", required = false, defaultValue = "true") Boolean descending, + @RequestParam(name = "orderBy", required = false, defaultValue = "created") String orderBy, + @RequestParam(name = "descending", required = false, defaultValue = "true") Boolean descending, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "3") int size ) { @@ -61,7 +63,7 @@ public class ExperimentApi { @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) public ResponseEntity<String> getExperiment( @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - ExperimentDTO experimentDTO = experimentService.getExperiment(uuid, "(GET) /experiments/{uuid}"); + ExperimentDTO experimentDTO = experimentService.getExperiment(uuid, "(GET) /experiments/{uuid}"); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); } @@ -69,15 +71,15 @@ public class ExperimentApi { @ApiOperation(value = "Create an experiment", response = ExperimentDTO.class) @RequestMapping(method = RequestMethod.POST) public ResponseEntity<String> createExperiment(Authentication authentication, @RequestBody ExperimentDTO experimentDTO) { - experimentDTO = experimentService.createExperiment(authentication, experimentDTO, "(POST) /experiments"); + experimentDTO = experimentService.createExperiment(authentication, experimentDTO, "(POST) /experiments"); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.CREATED); } @ApiOperation(value = "Create a transient experiment", response = ExperimentDTO.class) - @RequestMapping(value = "/transient",method = RequestMethod.POST) + @RequestMapping(value = "/transient", method = RequestMethod.POST) public ResponseEntity<String> createTransientExperiment(Authentication authentication, @RequestBody ExperimentDTO experimentDTO) { - experimentDTO = experimentService.createTransientExperiment(authentication, experimentDTO, "(POST) /experiments/transient"); + experimentDTO = experimentService.createTransientExperiment(authentication, experimentDTO, "(POST) /experiments/transient"); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); } @@ -85,7 +87,7 @@ public class ExperimentApi { @ApiOperation(value = "Update an experiment", response = ExperimentDTO.class) @RequestMapping(value = "/{uuid}", method = RequestMethod.PATCH) - public ResponseEntity<String> updateExperiment(@RequestBody ExperimentDTO experimentDTO,@ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + public ResponseEntity<String> updateExperiment(@RequestBody ExperimentDTO experimentDTO, @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { experimentDTO = experimentService.updateExperiment(uuid, experimentDTO, "(PATCH) /experiments/{uuid}"); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); } diff --git a/src/main/java/eu/hbp/mip/controllers/PathologiesApi.java b/src/main/java/eu/hbp/mip/controllers/PathologiesAPI.java similarity index 84% rename from src/main/java/eu/hbp/mip/controllers/PathologiesApi.java rename to src/main/java/eu/hbp/mip/controllers/PathologiesAPI.java index a6979e70ccae284adeed66bdf125f83e256987e9..f79052ff5e07e73ae14f5e96ec676e09727838fd 100644 --- a/src/main/java/eu/hbp/mip/controllers/PathologiesApi.java +++ b/src/main/java/eu/hbp/mip/controllers/PathologiesAPI.java @@ -1,13 +1,9 @@ -/** - * Created by mirco on 04.12.15. - */ - package eu.hbp.mip.controllers; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import eu.hbp.mip.model.DTOs.PathologyDTO; -import eu.hbp.mip.model.UserInfo; +import eu.hbp.mip.models.DTOs.PathologyDTO; +import eu.hbp.mip.services.ActiveUserService; import eu.hbp.mip.utils.ClaimUtils; import eu.hbp.mip.utils.CustomResourceLoader; import eu.hbp.mip.utils.Exceptions.BadRequestException; @@ -15,7 +11,6 @@ import eu.hbp.mip.utils.InputStreamConverter; import eu.hbp.mip.utils.Logging; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; @@ -32,20 +27,19 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RestController @RequestMapping(value = "/pathologies", produces = {APPLICATION_JSON_VALUE}) @Api(value = "/pathologies") -public class PathologiesApi { +public class PathologiesAPI { private static final Gson gson = new Gson(); - @Qualifier("userInfo") @Autowired - private UserInfo userInfo; + private ActiveUserService activeUserService; // Enable HBP collab authentication (1) or disable it (0). Default is 1 - @Value("#{'${hbp.authentication.enabled:1}'}") + @Value("#{'${authentication.enabled}'}") private boolean authenticationIsEnabled; - @Value("#{'${services.pathologies.pathologiesUrl}'}") - private String pathologiesUrl; + @Value("#{'${files.pathologies_json}'}") + private String pathologiesFilePath; @Autowired private CustomResourceLoader resourceLoader; @@ -53,11 +47,11 @@ public class PathologiesApi { @RequestMapping(name = "/pathologies", method = RequestMethod.GET) public ResponseEntity<String> getPathologies(Authentication authentication) { String endpoint = "(GET) /pathologies"; - String username = userInfo.getUser().getUsername(); + String username = activeUserService.getActiveUser().getUsername(); Logging.LogUserAction(username, endpoint, "Loading pathologies ..."); // Load pathologies from file - Resource resource = resourceLoader.getResource(pathologiesUrl); + Resource resource = resourceLoader.getResource(pathologiesFilePath); List<PathologyDTO> allPathologies; try { allPathologies = gson.fromJson(InputStreamConverter.convertInputStreamToString(resource.getInputStream()), new TypeToken<List<PathologyDTO>>() { diff --git a/src/main/java/eu/hbp/mip/controllers/SecurityApi.java b/src/main/java/eu/hbp/mip/controllers/SecurityApi.java deleted file mode 100644 index e179b3172446ddd9906f36bca3f7efe6b195c165..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/SecurityApi.java +++ /dev/null @@ -1,119 +0,0 @@ -package eu.hbp.mip.controllers; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import eu.hbp.mip.configuration.SecurityConfiguration; -import eu.hbp.mip.model.DAOs.UserDAO; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.repositories.UserRepository; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.ApiParam; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.security.Principal; -import java.util.Base64; - -@RestController -public class SecurityApi { - - private static final Gson gson = new Gson(); - - @Autowired - private UserInfo userInfo; - - @Autowired - private UserRepository userRepository; - - @Autowired - private SecurityConfiguration securityConfiguration; - - @RequestMapping(path = "/user", method = RequestMethod.GET) - public Object user(Principal principal, HttpServletResponse response) { - ObjectMapper mapper = new ObjectMapper(); - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /user", "Loading user : " + userInfo.getUser().getUsername()); - try { - String userJSON = mapper.writeValueAsString(userInfo.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("Cannot read user json", e); - } - - if (!securityConfiguration.getAuthenticationEnabled()) { - if (userInfo.isFakeAuth()) { - response.setStatus(401); - } - String principalJson = "{\"principal\": \"anonymous\", \"name\": \"anonymous\", \"userAuthentication\": {" - + "\"details\": {\"preferred_username\": \"anonymous\"}}}"; - return new Gson().fromJson(principalJson, Object.class); - } - - return principal; - } - - @RequestMapping(path = "/user", method = RequestMethod.POST) - public ResponseEntity<Void> postUser( - @ApiParam(value = "Has the user agreed on the NDA") @RequestParam(value = "agreeNDA") Boolean agreeNDA) { - UserDAO user = userInfo.getUser(); - if (user != null) { - user.setAgreeNDA(agreeNDA); - userRepository.save(user); - } - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /user", "User has agreed on the NDA"); - - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - @RequestMapping(path = "/login/hbp", method = RequestMethod.GET) - @ConditionalOnExpression("${hbp.authentication.enabled:0}") - public void noLogin(HttpServletResponse httpServletResponse) throws IOException { - userInfo.setFakeAuth(true); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /user/login/hbp", "Unauthorized login."); - - httpServletResponse.sendRedirect(securityConfiguration.getFrontendRedirectAfterLogin()); - } - - @Value("#{'${services.galaxy.galaxyUsername:admin}'}") - private String galaxyUsername; - - @Value("#{'${services.galaxy.galaxyPassword:password}'}") - private String galaxyPassword; - - @Value("#{'${services.galaxy.galaxyContext:nativeGalaxy}'}") - private String galaxyContext; - - /** - * Get Galaxy Reverse Proxy basic access token. - * - * @return Return a @{@link ResponseEntity} with the token. - */ - @RequestMapping(path = "/galaxy", method = RequestMethod.GET, produces = "application/json") - @PreAuthorize("hasRole('Data Manager')") - @ResponseStatus(value = HttpStatus.OK) - public ResponseEntity getGalaxyConfiguration() { - String stringEncoded = Base64.getEncoder().encodeToString((galaxyUsername + ":" + galaxyPassword).getBytes()); - JsonObject object = new JsonObject(); - object.addProperty("authorization", stringEncoded); - object.addProperty("context", galaxyContext); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /user/galaxy", "Successfully Loaded galaxy information."); - - return ResponseEntity.ok(gson.toJson(object)); - } -} diff --git a/src/main/java/eu/hbp/mip/controllers/UsersApi.java b/src/main/java/eu/hbp/mip/controllers/UsersApi.java deleted file mode 100644 index 886ad1ac90776e3c8b66025a6f7a22c223eadb6a..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/UsersApi.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Created by mirco on 14.01.16. - */ - -package eu.hbp.mip.controllers; - -import eu.hbp.mip.model.DAOs.UserDAO; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.repositories.UserRepository; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -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.RestController; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -@RestController -@RequestMapping(value = "/users", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/users", description = "the users API") -public class UsersApi { - - @Autowired - private UserRepository userRepository; - - @Autowired - private UserInfo userInfo; - - @ApiOperation(value = "Get a user", response = UserDAO.class) - @RequestMapping(value = "/{username}", method = RequestMethod.GET) - public ResponseEntity<UserDAO> getAUser( - @ApiParam(value = "username", required = true) @PathVariable("username") String username - ) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /users/{username}", "Loaded a user with username : " + userInfo.getUser().getUsername()); - - return ResponseEntity.ok(userRepository.findByUsername(username)); - } -} diff --git a/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java index 612dce6ca5b557f23deafdf873978c0f442eb1d9..609163e8920ad3443e908c36aea6143ba69533c1 100644 --- a/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java +++ b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java @@ -1,9 +1,9 @@ package eu.hbp.mip.controllers.galaxy.retrofit; import com.google.gson.JsonObject; -import eu.hbp.mip.model.galaxy.GalaxyWorkflowResult; -import eu.hbp.mip.model.galaxy.PostWorkflowToGalaxyDtoResponse; -import eu.hbp.mip.model.galaxy.WorkflowDTO; +import eu.hbp.mip.models.galaxy.GalaxyWorkflowResult; +import eu.hbp.mip.models.galaxy.PostWorkflowToGalaxyDtoResponse; +import eu.hbp.mip.models.galaxy.WorkflowDTO; import retrofit2.Call; import retrofit2.http.*; diff --git a/src/main/java/eu/hbp/mip/model/DAOs/ArticleDAO.java b/src/main/java/eu/hbp/mip/model/DAOs/ArticleDAO.java deleted file mode 100644 index 541c50765e25e7ce68504026ed437f906104e2ce..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/DAOs/ArticleDAO.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model.DAOs; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import org.springframework.validation.annotation.Validated; - -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.Date; - -@Entity -@Table(name = "`article`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -@Validated -public class ArticleDAO { - - @Id - private String slug = null; - - @NotNull - @Size(min = 1, max = 255) - private String title; - - private String status = null; - - @Column(columnDefinition = "text", name = "abstract") - private String abstractText = null; - - @Column(columnDefinition = "text") - private String content = null; - - private Date publishedAt = null; - - private Date createdAt = null; - - private Date updatedAt = null; - - @ManyToOne - @JoinColumn(name = "createdby_username") - private UserDAO createdBy = null; - - @ManyToOne - @JoinColumn(name = "updatedby_username") - private UserDAO updatedBy = null; - - public ArticleDAO() { - /* - * Empty constructor is needed by Hibernate - */ - title = ""; - } - - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - - public String getSlug() { - return slug; - } - - public void setSlug(String slug) { - this.slug = slug; - } - - - @JsonProperty("abstract") - public String getAbstract() { - return abstractText; - } - - public void setAbstract(String abstractText) { - this.abstractText = abstractText; - } - - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - - public Date getPublishedAt() { - return publishedAt; - } - - public void setPublishedAt(Date publishedAt) { - this.publishedAt = publishedAt; - } - - - public Date getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } - - - public Date getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; - } - - - public UserDAO getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(UserDAO createdBy) { - this.createdBy = createdBy; - } - - - public UserDAO getUpdatedBy() { - return updatedBy; - } - - public void setUpdatedBy(UserDAO updatedBy) { - this.updatedBy = updatedBy; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/DAOs/UserDAO.java b/src/main/java/eu/hbp/mip/model/DAOs/UserDAO.java deleted file mode 100644 index 1e35ac8315e000e21c6962472967b53fbdcaecf9..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/DAOs/UserDAO.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model.DAOs; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.google.gson.annotations.Expose; -import io.swagger.annotations.ApiModel; - -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@Entity -@Table(name = "`user`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(value = {"appsVotes"}) -public class UserDAO { - - @Id - @Expose - private String username = null; - - @Expose - private String fullname = null; - - @Expose - private String email = null; - - private Boolean agreeNDA = null; - - - public UserDAO() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - /** - * Create a user using OpenID user profile - * - * @param userInfo info from OpenID UserInfo endpoint - */ - public UserDAO(String userInfo) { - - Pattern p; - Matcher m; - - p = Pattern.compile("preferred_username=([\\w- ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.username = m.group(1); - } - - p = Pattern.compile("name=([\\w ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.fullname = m.group(1); - } - - p = Pattern.compile("email=([\\w.]+@[\\w.]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.email = m.group(1); - } - - - } - - - public String getFullname() { - return fullname; - } - - public void setFullname(String fullname) { - this.fullname = fullname; - } - - - 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 Boolean getAgreeNDA() { - return agreeNDA; - } - - public void setAgreeNDA(Boolean agreeNDA) { - this.agreeNDA = agreeNDA; - } -} diff --git a/src/main/java/eu/hbp/mip/model/GeneralStats.java b/src/main/java/eu/hbp/mip/model/GeneralStats.java deleted file mode 100644 index 4253ae7dd859ed63a47ffba68a9bcafc5646302c..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/GeneralStats.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Created by mirco on 03.02.16. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; - -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class GeneralStats { - - private Long users = null; - private Long articles = null; - - - public GeneralStats() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public Long getUsers() { - return users; - } - - public void setUsers(Long users) { - this.users = users; - } - - - public Long getArticles() { - return articles; - } - - public void setArticles(Long articles) { - this.articles = articles; - } -} diff --git a/src/main/java/eu/hbp/mip/model/UserInfo.java b/src/main/java/eu/hbp/mip/model/UserInfo.java deleted file mode 100644 index cb61cfcea60c58275aaa0fac65c63a699efd58c7..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/UserInfo.java +++ /dev/null @@ -1,84 +0,0 @@ -package eu.hbp.mip.model; - -import eu.hbp.mip.model.DAOs.UserDAO; -import eu.hbp.mip.repositories.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.stereotype.Component; - -import javax.inject.Named; - -@Component -@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) -@Named("userInfo") -public class UserInfo { - - @Autowired - private UserRepository userRepository; - - /** - * Enable HBP collab authentication (1) or disable it (0). Default is 1 - */ - @Value("#{'${hbp.authentication.enabled:1}'}") - private boolean authentication; - - private UserDAO user; - - /** - * Set to true if using no-auth mode and user has clicked on the login button - */ - private boolean fakeAuth = false; - - /** - * 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 the user for the current session - */ - public UserDAO getUser() { - if (user == null) { - - if (!authentication) { - user = new UserDAO(); - user.setUsername("anonymous"); - user.setFullname("anonymous"); - user.setEmail("anonymous@anonymous.com"); - } else { - user = new UserDAO(getUserInfos()); - } - UserDAO foundUser = userRepository.findByUsername(user.getUsername()); - if (foundUser != null) { - user.setAgreeNDA(foundUser.getAgreeNDA()); - } - userRepository.save(user); - } - - return user; - } - - public boolean isFakeAuth() { - return fakeAuth; - } - - public void setFakeAuth(boolean fakeAuth) { - this.fakeAuth = fakeAuth; - } - - private String getUserInfos() { - OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication(); - Authentication userAuthentication = oAuth2Authentication.getUserAuthentication(); - return userAuthentication.getDetails().toString(); - } - -} diff --git a/src/main/java/eu/hbp/mip/model/DAOs/ExperimentDAO.java b/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java similarity index 97% rename from src/main/java/eu/hbp/mip/model/DAOs/ExperimentDAO.java rename to src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java index f10f887426f189917fe2dd9f632a21e95df6192d..1cf4864bdb1a1d6a568831eb93f5b6ce7f1168cd 100644 --- a/src/main/java/eu/hbp/mip/model/DAOs/ExperimentDAO.java +++ b/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java @@ -1,10 +1,10 @@ -package eu.hbp.mip.model.DAOs; +package eu.hbp.mip.models.DAOs; import com.fasterxml.jackson.annotation.JsonInclude; import com.google.gson.Gson; import com.google.gson.annotations.Expose; -import eu.hbp.mip.model.DTOs.AlgorithmDTO; -import eu.hbp.mip.model.DTOs.ExperimentDTO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; +import eu.hbp.mip.models.DTOs.ExperimentDTO; import eu.hbp.mip.utils.JsonConverters; import io.swagger.annotations.ApiModel; import org.svenson.JSONParser; diff --git a/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java b/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..a94e5da1c177648965a8f3f192356fa5c2da8a07 --- /dev/null +++ b/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java @@ -0,0 +1,76 @@ +/* + * Created by mirco on 04.12.15. + */ + +package eu.hbp.mip.models.DAOs; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.google.gson.annotations.Expose; +import io.swagger.annotations.ApiModel; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "`user`") +@ApiModel +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserDAO { + + @Id + @Expose + private String username; + + @Expose + private String fullname; + + @Expose + private String email; + + @Expose + private Boolean agreeNDA; + + public UserDAO() { + // Empty constructor is needed by Hibernate + } + + public UserDAO(String username, String fullname, String email) { + this.username = username; + this.fullname = fullname; + this.email = email; + this.agreeNDA = false; + } + + public String getFullname() { + return fullname; + } + + public void setFullname(String fullname) { + this.fullname = fullname; + } + + 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 Boolean getAgreeNDA() { + return agreeNDA; + } + + public void setAgreeNDA(Boolean agreeNDA) { + this.agreeNDA = agreeNDA; + } +} diff --git a/src/main/java/eu/hbp/mip/model/DTOs/AlgorithmDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/AlgorithmDTO.java similarity index 95% rename from src/main/java/eu/hbp/mip/model/DTOs/AlgorithmDTO.java rename to src/main/java/eu/hbp/mip/models/DTOs/AlgorithmDTO.java index 0a49c5ad672aa0b14e6830bf6d683f95a08af6b4..1a6d8b99d41b4129c85b2b3591cc6ea3f89c950f 100644 --- a/src/main/java/eu/hbp/mip/model/DTOs/AlgorithmDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/AlgorithmDTO.java @@ -1,4 +1,4 @@ -package eu.hbp.mip.model.DTOs; +package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/DTOs/ExperimentDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java similarity index 97% rename from src/main/java/eu/hbp/mip/model/DTOs/ExperimentDTO.java rename to src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java index 037ab5767cec70daa49320fa228c73cc5b1f7a8e..8c6073a1f0d0b6f1cb3db26deb1e7b4e8586daeb 100644 --- a/src/main/java/eu/hbp/mip/model/DTOs/ExperimentDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java @@ -1,6 +1,6 @@ -package eu.hbp.mip.model.DTOs; +package eu.hbp.mip.models.DTOs; -import eu.hbp.mip.model.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.ExperimentDAO; import java.util.Date; import java.util.Map; diff --git a/src/main/java/eu/hbp/mip/model/DTOs/PathologyDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java similarity index 93% rename from src/main/java/eu/hbp/mip/model/DTOs/PathologyDTO.java rename to src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java index 6a4580e81bbf9e7e371cf4c8297723d3b946f9c0..2a8887b5f22a309ecf2befcc69e1191a7c00576c 100644 --- a/src/main/java/eu/hbp/mip/model/DTOs/PathologyDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java @@ -1,4 +1,4 @@ -package eu.hbp.mip.model.DTOs; +package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/ErrorResponse.java b/src/main/java/eu/hbp/mip/models/galaxy/ErrorResponse.java similarity index 96% rename from src/main/java/eu/hbp/mip/model/galaxy/ErrorResponse.java rename to src/main/java/eu/hbp/mip/models/galaxy/ErrorResponse.java index 77a171358b54561e3492dcb317acd835aeaa645f..2703e742541faf9f715ed19485076d397697059e 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/ErrorResponse.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/ErrorResponse.java @@ -3,7 +3,7 @@ * Copyright (c) 2019. MIT License */ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/GalaxyWorkflowResult.java b/src/main/java/eu/hbp/mip/models/galaxy/GalaxyWorkflowResult.java similarity index 99% rename from src/main/java/eu/hbp/mip/model/galaxy/GalaxyWorkflowResult.java rename to src/main/java/eu/hbp/mip/models/galaxy/GalaxyWorkflowResult.java index 089a6a626ed1e0d38306c911b515edd3fa8fa5f0..ca7d98fe51e55cd60914893283f2c30b6fcf90be 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/GalaxyWorkflowResult.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/GalaxyWorkflowResult.java @@ -3,7 +3,7 @@ * Copyright (c) 2019. MIT License */ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/PostWorkflowToGalaxyDtoResponse.java b/src/main/java/eu/hbp/mip/models/galaxy/PostWorkflowToGalaxyDtoResponse.java similarity index 98% rename from src/main/java/eu/hbp/mip/model/galaxy/PostWorkflowToGalaxyDtoResponse.java rename to src/main/java/eu/hbp/mip/models/galaxy/PostWorkflowToGalaxyDtoResponse.java index edefd63266a8d1678bf82d057882e4eccab112cc..96d8aa8efa089599093fed13ac8e0d0a4be81f42 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/PostWorkflowToGalaxyDtoResponse.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/PostWorkflowToGalaxyDtoResponse.java @@ -3,7 +3,7 @@ * Copyright (c) 2019. MIT License */ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/WorkflowDTO.java b/src/main/java/eu/hbp/mip/models/galaxy/WorkflowDTO.java similarity index 95% rename from src/main/java/eu/hbp/mip/model/galaxy/WorkflowDTO.java rename to src/main/java/eu/hbp/mip/models/galaxy/WorkflowDTO.java index 4b01b38198d52e25d0f9455f770a9a5918d77874..496ee2dfebf50324b1443774cc48edd4e32c2de0 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/WorkflowDTO.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/WorkflowDTO.java @@ -1,8 +1,8 @@ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; -import eu.hbp.mip.model.DTOs.AlgorithmDTO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; import java.util.*; diff --git a/src/main/java/eu/hbp/mip/repositories/ArticleRepository.java b/src/main/java/eu/hbp/mip/repositories/ArticleRepository.java deleted file mode 100644 index 5f6589ab5e61499aff08022ed0af52efb1e2edc0..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/ArticleRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.DAOs.ArticleDAO; -import eu.hbp.mip.model.DAOs.UserDAO; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface ArticleRepository extends CrudRepository<ArticleDAO, String> { - Long countByTitle(String title); - - Iterable<ArticleDAO> findByCreatedBy(UserDAO user); - - Iterable<ArticleDAO> findByStatusOrCreatedBy(String status, UserDAO user); -} diff --git a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java index 7b30600e5d5575aa9a2b2f12909820382aec2142..9ac54cada906b78ad5ab5ac41d77d05562bedc4e 100644 --- a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java +++ b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java @@ -1,6 +1,6 @@ package eu.hbp.mip.repositories; -import eu.hbp.mip.model.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.ExperimentDAO; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; diff --git a/src/main/java/eu/hbp/mip/repositories/UserRepository.java b/src/main/java/eu/hbp/mip/repositories/UserRepository.java index 4a3a7c69893f01a20f5cf860498bdfd1173a62bf..99ae0b1dcfc237e875e7ba458175ae8441ec8c8e 100644 --- a/src/main/java/eu/hbp/mip/repositories/UserRepository.java +++ b/src/main/java/eu/hbp/mip/repositories/UserRepository.java @@ -1,6 +1,6 @@ package eu.hbp.mip.repositories; -import eu.hbp.mip.model.DAOs.UserDAO; +import eu.hbp.mip.models.DAOs.UserDAO; import org.springframework.data.repository.CrudRepository; /** diff --git a/src/main/java/eu/hbp/mip/services/ActiveUserService.java b/src/main/java/eu/hbp/mip/services/ActiveUserService.java new file mode 100644 index 0000000000000000000000000000000000000000..5004e1f7f92dfc96e7f4decbf007c7dc442ae370 --- /dev/null +++ b/src/main/java/eu/hbp/mip/services/ActiveUserService.java @@ -0,0 +1,75 @@ +package eu.hbp.mip.services; + +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.repositories.UserRepository; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.representations.IDToken; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +import javax.inject.Named; + +@Component +@Named("ActiveUserService") +@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) +public class ActiveUserService { + + @Value("#{'${authentication.enabled}'}") + private boolean authentication; + + private UserDAO user; + + @Autowired + private UserRepository userRepository; + + /** + * Fetches the details of the active user. + * If the user doesn't exist, it's created on the fly from the auth token. + * + * @return the userDAO + */ + public UserDAO getActiveUser() { + + // User already loaded + if (user != null) + return user; + + // If Authentication is OFF, create anonymous user with accepted NDA + if (!authentication) { + user = new UserDAO("anonymous", "anonymous", "anonymous@anonymous.com"); + user.setAgreeNDA(true); + userRepository.save(user); + return user; + } + + + // TODO Update user if new values are providedTO + // If authentication is ON get user info from Token + KeycloakPrincipal keycloakPrincipal = + (KeycloakPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + IDToken idToken = keycloakPrincipal.getKeycloakSecurityContext().getIdToken(); + UserDAO userInDatabase = userRepository.findByUsername(idToken.getPreferredUsername()); + if (userInDatabase != null) { + user = userInDatabase; + } else { + UserDAO newUser = new UserDAO(idToken.getPreferredUsername(), idToken.getName(), idToken.getEmail()); + userRepository.save(newUser); + user = newUser; + } + return user; + } + + public UserDAO agreeToNDA() { + // Fetch the active user + getActiveUser(); + + user.setAgreeNDA(true); + userRepository.save(user); + + return user; + } +} diff --git a/src/main/java/eu/hbp/mip/services/ExperimentService.java b/src/main/java/eu/hbp/mip/services/ExperimentService.java index 12c0d126942063868c09334bc8fe456489d95238..ed5c8edd87775c3f94607ec9c0515dd5de72b518 100644 --- a/src/main/java/eu/hbp/mip/services/ExperimentService.java +++ b/src/main/java/eu/hbp/mip/services/ExperimentService.java @@ -12,13 +12,12 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; -import eu.hbp.mip.model.DAOs.ExperimentDAO; -import eu.hbp.mip.model.DAOs.UserDAO; -import eu.hbp.mip.model.DTOs.AlgorithmDTO; -import eu.hbp.mip.model.DTOs.ExperimentDTO; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.model.galaxy.GalaxyWorkflowResult; -import eu.hbp.mip.model.galaxy.PostWorkflowToGalaxyDtoResponse; +import eu.hbp.mip.models.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.models.galaxy.GalaxyWorkflowResult; +import eu.hbp.mip.models.galaxy.PostWorkflowToGalaxyDtoResponse; import eu.hbp.mip.repositories.ExperimentRepository; import eu.hbp.mip.utils.ClaimUtils; import eu.hbp.mip.utils.Exceptions.*; @@ -27,7 +26,6 @@ import eu.hbp.mip.utils.JsonConverters; import eu.hbp.mip.utils.Logging; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -56,38 +54,38 @@ public class ExperimentService { @Value("#{'${services.galaxy.galaxyApiKey}'}") private String galaxyApiKey; - // Enable HBP collab authentication (1) or disable it (0). Default is 1 - @Value("#{'${hbp.authentication.enabled:1}'}") + @Value("#{'${authentication.enabled}'}") private boolean authenticationIsEnabled; private static final Gson gson = new Gson(); - private final UserInfo userInfo; + private ActiveUserService activeUserService; private final ExperimentRepository experimentRepository; - public ExperimentService(@Qualifier("userInfo") UserInfo userInfo, ExperimentRepository experimentRepository) { - this.userInfo = userInfo; + public ExperimentService(ActiveUserService activeUserService, ExperimentRepository experimentRepository) { + this.activeUserService = activeUserService; this.experimentRepository = experimentRepository; } /** * The getExperiments will retrieve the experiments from database according to the filters. * - * @param name is optional, in case it is required to filter the experiments by name - * @param algorithm is optional, in case it is required to filter the experiments by algorithm name - * @param shared is optional, in case it is required to filter the experiments by shared - * @param viewed is optional, in case it is required to filter the experiments by viewed - * @param page is the page that is required to be retrieve - * @param size is the size of each page - * @param orderBy is the column that is required to ordered by + * @param name is optional, in case it is required to filter the experiments by name + * @param algorithm is optional, in case it is required to filter the experiments by algorithm name + * @param shared is optional, in case it is required to filter the experiments by shared + * @param viewed is optional, in case it is required to filter the experiments by viewed + * @param page is the page that is required to be retrieve + * @param size is the size of each page + * @param orderBy is the column that is required to ordered by * @param descending is a boolean to determine if the experiments will be order by descending or ascending - * @param endpoint is the endpoint that called the function + * @param endpoint is the endpoint that called the function * @return a list of mapped experiments */ - public Map getExperiments(String name,String algorithm, Boolean shared,Boolean viewed, int page, int size, String orderBy, Boolean descending, String endpoint) { - UserDAO user = userInfo.getUser(); + + public Map getExperiments(String name, String algorithm, Boolean shared, Boolean viewed, int page, int size, String orderBy, Boolean descending, String endpoint) { + UserDAO user = activeUserService.getActiveUser(); Logging.LogUserAction(user.getUsername(), endpoint, "Listing my experiments."); - if(size > 10 ) + if (size > 10) throw new BadRequestException("Invalid size input, max size is 10."); Specification<ExperimentDAO> spec = Specification @@ -98,7 +96,7 @@ public class ExperimentService { .and(new ExperimentSpecifications.ExperimentOrderBy(orderBy, descending)); Pageable paging = PageRequest.of(page, size); - Page<ExperimentDAO> pageExperiments = experimentRepository.findAll(spec, paging); + Page<ExperimentDAO> pageExperiments = experimentRepository.findAll(spec, paging); List<ExperimentDAO> experimentDAOs = pageExperiments.getContent(); if (experimentDAOs.isEmpty()) @@ -119,14 +117,14 @@ public class ExperimentService { /** * The getExperiment will retrieve the experiment from database according to the input uuid * - * @param uuid is the id of the experiment to be retrieved + * @param uuid is the id of the experiment to be retrieved * @param endpoint is the endpoint that called the function * @return the experiment information that was retrieved from the database */ public ExperimentDTO getExperiment(String uuid, String endpoint) { ExperimentDAO experimentDAO; - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); Logging.LogUserAction(user.getUsername(), endpoint, "Loading Experiment with uuid : " + uuid); @@ -146,12 +144,12 @@ public class ExperimentService { * The createExperiment will create and save an experiment in the database. * * @param authentication is the role of the user - * @param experimentDTO is the experiment information - * @param endpoint is the endpoint that called the function + * @param experimentDTO is the experiment information + * @param endpoint is the endpoint that called the function * @return the experiment information which was created */ public ExperimentDTO createExperiment(Authentication authentication, ExperimentDTO experimentDTO, String endpoint) { - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); //Checking if check (POST) /experiments has proper input. checkPostExperimentProperInput(experimentDTO, endpoint); @@ -180,12 +178,12 @@ public class ExperimentService { * The createTransientExperiment will run synchronous a transient experiment into exareme and provide results * * @param authentication is the role of the user - * @param experimentDTO is the experiment information - * @param endpoint is the endpoint that called the function + * @param experimentDTO is the experiment information + * @param endpoint is the endpoint that called the function * @return the experiment information which was created */ - public ExperimentDTO createTransientExperiment(Authentication authentication, ExperimentDTO experimentDTO, String endpoint){ - UserDAO user = userInfo.getUser(); + public ExperimentDTO createTransientExperiment(Authentication authentication, ExperimentDTO experimentDTO, String endpoint) { + UserDAO user = activeUserService.getActiveUser(); //Checking if check (POST) /experiments has proper input. checkPostExperimentProperInput(experimentDTO, endpoint); @@ -197,7 +195,7 @@ public class ExperimentService { // Get the type and name of algorithm String algorithmName = experimentDTO.getAlgorithmDetails().getName(); - if (!allowedTransientAlgorithms(algorithmName)){ + if (!allowedTransientAlgorithms(algorithmName)) { Logging.LogUserAction(user.getUsername(), endpoint, "Not proper algorithm."); throw new BadRequestException("Please provide proper algorithm."); @@ -220,10 +218,10 @@ public class ExperimentService { // Results are stored in the experiment object ExaremeResult exaremeResult = runExaremeExperiment(url, body, experimentDTO); - Logging.LogUserAction(user.getUsername(), endpoint, "Experiment with uuid: " + experimentDTO.getUuid() + "gave response code: " +exaremeResult.getCode() + " and result: "+ exaremeResult.getResults()); + Logging.LogUserAction(user.getUsername(), endpoint, "Experiment with uuid: " + experimentDTO.getUuid() + "gave response code: " + exaremeResult.getCode() + " and result: " + exaremeResult.getResults()); - experimentDTO.setResult((exaremeResult.getCode()>= 400)? null: exaremeResult.getResults()); - experimentDTO.setStatus((exaremeResult.getCode()>= 400)? ExperimentDAO.Status.error: ExperimentDAO.Status.success); + experimentDTO.setResult((exaremeResult.getCode() >= 400) ? null : exaremeResult.getResults()); + experimentDTO.setStatus((exaremeResult.getCode() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); return experimentDTO; } @@ -231,40 +229,38 @@ public class ExperimentService { /** * The updateExperiment will update the experiment's properties * - * @param uuid is the id of the experiment to be updated + * @param uuid is the id of the experiment to be updated * @param experimentDTO is the experiment information to be updated - * @param endpoint is the endpoint that called the function + * @param endpoint is the endpoint that called the function * @return the updated experiment information */ - public ExperimentDTO updateExperiment(String uuid, ExperimentDTO experimentDTO, String endpoint) - { + public ExperimentDTO updateExperiment(String uuid, ExperimentDTO experimentDTO, String endpoint) { ExperimentDAO experimentDAO; - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); Logging.LogUserAction(user.getUsername(), endpoint, "Updating experiment with uuid : " + uuid + "."); experimentDAO = loadExperiment(uuid, endpoint); //Verify (PATCH) /experiments non editable fields. verifyPatchExperimentNonEditableFields(uuid, experimentDTO, experimentDAO, endpoint); - + if (!experimentDAO.getCreatedBy().getUsername().equals(user.getUsername())) throw new UnauthorizedException("You don't have access to the experiment."); - if(experimentDTO.getName() != null && experimentDTO.getName().length() != 0) + if (experimentDTO.getName() != null && experimentDTO.getName().length() != 0) experimentDAO.setName(experimentDTO.getName()); - if(experimentDTO.getShared() != null) + if (experimentDTO.getShared() != null) experimentDAO.setShared(experimentDTO.getShared()); - if(experimentDTO.getViewed() != null) + if (experimentDTO.getViewed() != null) experimentDAO.setViewed(experimentDTO.getViewed()); experimentDAO.setUpdated(new Date()); try { experimentRepository.save(experimentDAO); - } - catch (Exception e){ + } catch (Exception e) { Logging.LogUserAction(user.getUsername(), endpoint, "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); throw new InternalServerError(e.getMessage()); } @@ -278,13 +274,12 @@ public class ExperimentService { /** * The deleteExperiment will delete an experiment from the database * - * @param uuid is the id of the experiment to be deleted + * @param uuid is the id of the experiment to be deleted * @param endpoint is the endpoint that called the function */ - public void deleteExperiment(String uuid, String endpoint) - { + public void deleteExperiment(String uuid, String endpoint) { ExperimentDAO experimentDAO; - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); Logging.LogUserAction(user.getUsername(), endpoint, "Deleting experiment with uuid : " + uuid + "."); experimentDAO = loadExperiment(uuid, endpoint); @@ -294,8 +289,7 @@ public class ExperimentService { try { experimentRepository.delete(experimentDAO); - } - catch (Exception e){ + } catch (Exception e) { Logging.LogUserAction(user.getUsername(), endpoint, "Attempted to delete an experiment to database but an error ocurred : " + e.getMessage() + "."); throw new InternalServerError(e.getMessage()); } @@ -305,72 +299,69 @@ public class ExperimentService { // /* ------------------------------- PRIVATE METHODS ----------------------------------------------------*/ - private void checkPostExperimentProperInput(ExperimentDTO experimentDTO, String endpoint) - { + private void checkPostExperimentProperInput(ExperimentDTO experimentDTO, String endpoint) { boolean properInput = - experimentDTO.getShared() == null - && experimentDTO.getViewed() == null - && experimentDTO.getCreated() == null - && experimentDTO.getCreatedBy() == null - && experimentDTO.getResult() == null - && experimentDTO.getStatus() == null - && experimentDTO.getUuid() == null; - - if (!properInput){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Invalid input."); + experimentDTO.getShared() == null + && experimentDTO.getViewed() == null + && experimentDTO.getCreated() == null + && experimentDTO.getCreatedBy() == null + && experimentDTO.getResult() == null + && experimentDTO.getStatus() == null + && experimentDTO.getUuid() == null; + + if (!properInput) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Invalid input."); throw new BadRequestException("Please provide proper input."); } } - private boolean allowedTransientAlgorithms(String algorithmName) - { + private boolean allowedTransientAlgorithms(String algorithmName) { List<String> properAlgorithms = new ArrayList<>(); properAlgorithms.add("MULTIPLE_HISTOGRAMS"); properAlgorithms.add("DESCRIPTIVE_STATS"); return properAlgorithms.contains(algorithmName); } - private void verifyPatchExperimentNonEditableFields(String uuid , ExperimentDTO experimentDTO, ExperimentDAO experimentDAO, String endpoint) - { - if(experimentDTO.getUuid() != null && experimentDTO.getUuid().toString().compareTo(uuid) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Uuid is not editable."); + private void verifyPatchExperimentNonEditableFields(String uuid, ExperimentDTO experimentDTO, ExperimentDAO experimentDAO, String endpoint) { + if (experimentDTO.getUuid() != null && experimentDTO.getUuid().toString().compareTo(uuid) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Uuid is not editable."); throw new BadRequestException("Uuid is not editable."); } - - if(experimentDTO.getAlgorithm() != null && experimentDTO.getAlgorithm().compareTo(experimentDAO.getAlgorithm()) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Algorithm is not editable."); + + if (experimentDTO.getAlgorithm() != null && experimentDTO.getAlgorithm().compareTo(experimentDAO.getAlgorithm()) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Algorithm is not editable."); throw new BadRequestException("Algorithm is not editable."); } - if(experimentDTO.getCreated() != null && experimentDTO.getCreatedBy().compareTo(experimentDAO.getCreatedBy().getUsername()) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "CreatedBy is not editable."); + if (experimentDTO.getCreated() != null && experimentDTO.getCreatedBy().compareTo(experimentDAO.getCreatedBy().getUsername()) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "CreatedBy is not editable."); throw new BadRequestException("CreatedBy is not editable."); } - if(experimentDTO.getAlgorithmDetails() != null && JsonConverters.convertObjectToJsonString(experimentDTO.getAlgorithmDetails()).compareTo(experimentDAO.getAlgorithmDetails()) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "AlgorithmDetails is not editable."); + if (experimentDTO.getAlgorithmDetails() != null && JsonConverters.convertObjectToJsonString(experimentDTO.getAlgorithmDetails()).compareTo(experimentDAO.getAlgorithmDetails()) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "AlgorithmDetails is not editable."); throw new BadRequestException("AlgorithmDetails is not editable."); } - - if(experimentDTO.getCreated() != null && experimentDTO.getAlgorithm().compareTo(experimentDAO.getAlgorithm()) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Created is not editable."); + + if (experimentDTO.getCreated() != null && experimentDTO.getAlgorithm().compareTo(experimentDAO.getAlgorithm()) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Created is not editable."); throw new BadRequestException("Created is not editable."); } - - if(experimentDTO.getResult() != null && JsonConverters.convertObjectToJsonString(experimentDTO.getResult()).compareTo(experimentDAO.getResult()) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Status is not editable."); + + if (experimentDTO.getResult() != null && JsonConverters.convertObjectToJsonString(experimentDTO.getResult()).compareTo(experimentDAO.getResult()) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Status is not editable."); throw new BadRequestException("Status is not editable."); } - - if(experimentDTO.getStatus() != null && experimentDTO.getStatus().compareTo(experimentDAO.getStatus()) != 0){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Status is not editable."); + + if (experimentDTO.getStatus() != null && experimentDTO.getStatus().compareTo(experimentDAO.getStatus()) != 0) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Status is not editable."); throw new BadRequestException("Status is not editable."); } } private void algorithmParametersLogging(ExperimentDTO experimentDTO, String endpoint) { - UserDAO user = userInfo.getUser() ; + UserDAO user = activeUserService.getActiveUser(); String algorithmName = experimentDTO.getAlgorithm(); StringBuilder parametersLogMessage = new StringBuilder(", Parameters:\n"); experimentDTO.getAlgorithmDetails().getParameters().forEach( @@ -379,7 +370,7 @@ public class ExperimentService { .append(params.getLabel()) .append(" -> ") .append(params.getValue()) - .append("\n") ); + .append("\n")); Logging.LogUserAction(user.getUsername(), endpoint, "Executing " + algorithmName + parametersLogMessage); } @@ -387,7 +378,7 @@ public class ExperimentService { * The getDatasetFromExperimentParameters will retrieve the dataset from the experiment parameters * * @param experimentDTO is the experiment information - * @param endpoint is the endpoint that called the function + * @param endpoint is the endpoint that called the function * @return the dataset from the experiment */ private String getDatasetFromExperimentParameters(ExperimentDTO experimentDTO, String endpoint) { @@ -401,7 +392,7 @@ public class ExperimentService { } if (experimentDatasets == null || experimentDatasets.equals("")) { - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "A dataset should be specified to run an algorithm."); throw new BadRequestException("Please provide at least one dataset to run the algorithm."); } @@ -414,22 +405,20 @@ public class ExperimentService { * @param uuid is the id of the experiment to be retrieved * @return the experiment information that was retrieved from database */ - private ExperimentDAO loadExperiment(String uuid, String endpoint){ - UUID experimentUuid ; + private ExperimentDAO loadExperiment(String uuid, String endpoint) { + UUID experimentUuid; ExperimentDAO experimentDAO; try { experimentUuid = UUID.fromString(uuid); - } - catch (Exception e) - { - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, e.getMessage()); + } catch (Exception e) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, e.getMessage()); throw new BadRequestException(e.getMessage()); } experimentDAO = experimentRepository.findByUuid(experimentUuid); - if (experimentDAO == null){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Experiment with uuid : " + uuid + "was not found."); + if (experimentDAO == null) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Experiment with uuid : " + uuid + "was not found."); throw new ExperimentNotFoundException("Experiment with uuid : " + uuid + " was not found."); } @@ -443,8 +432,7 @@ public class ExperimentService { * @return the experiment information that was inserted into the database */ private ExperimentDAO createExperimentInTheDatabase(ExperimentDTO experimentDTO, String endpoint) { - - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); ExperimentDAO experimentDAO = new ExperimentDAO(); experimentDAO.setUuid(UUID.randomUUID()); @@ -456,8 +444,7 @@ public class ExperimentService { try { experimentRepository.save(experimentDAO); - } - catch (Exception e){ + } catch (Exception e) { Logging.LogUserAction(user.getUsername(), endpoint, "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); throw new InternalServerError(e.getMessage()); } @@ -469,7 +456,7 @@ public class ExperimentService { } private void saveExperiment(ExperimentDAO experimentDAO, String endpoint) { - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); Logging.LogUserAction(user.getUsername(), endpoint, " id : " + experimentDAO.getUuid()); Logging.LogUserAction(user.getUsername(), endpoint, " algorithms : " + experimentDAO.getAlgorithmDetails()); @@ -479,8 +466,7 @@ public class ExperimentService { try { experimentRepository.save(experimentDAO); - } - catch (Exception e){ + } catch (Exception e) { Logging.LogUserAction(user.getUsername(), endpoint, "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); throw new InternalServerError(e.getMessage()); } @@ -493,9 +479,8 @@ public class ExperimentService { try { experimentRepository.save(experimentDAO); - } - catch (Exception e){ - Logging.LogUserAction(userInfo.getUser().getUsername(), endpoint, "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + } catch (Exception e) { + Logging.LogUserAction(activeUserService.getActiveUser().getUsername(), endpoint, "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); throw new InternalServerError(e.getMessage()); } } @@ -506,12 +491,12 @@ public class ExperimentService { * The createExaremeExperiment will POST the algorithm to the exareme client * * @param experimentDTO is the request with the experiment information - * @param endpoint is the endpoint that called the function + * @param endpoint is the endpoint that called the function * @return the experiment information that was retrieved from exareme */ public ExperimentDTO createExaremeExperiment(ExperimentDTO experimentDTO, String endpoint) { + UserDAO user = activeUserService.getActiveUser(); - UserDAO user = userInfo.getUser(); Logging.LogUserAction(user.getUsername(), endpoint, "Running the algorithm..."); ExperimentDAO experimentDAO = createExperimentInTheDatabase(experimentDTO, endpoint); @@ -543,10 +528,10 @@ public class ExperimentService { // Results are stored in the experiment object ExaremeResult exaremeResult = runExaremeExperiment(url, body, finalExperimentDTO); - Logging.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Experiment with uuid: " + experimentDAO.getUuid() + "gave response code: " +exaremeResult.getCode() + " and result: "+ exaremeResult.getResults()); + Logging.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Experiment with uuid: " + experimentDAO.getUuid() + "gave response code: " + exaremeResult.getCode() + " and result: " + exaremeResult.getResults()); - experimentDAO.setResult((exaremeResult.getCode()>= 400)? null : JsonConverters.convertObjectToJsonString(exaremeResult.getResults())); - experimentDAO.setStatus((exaremeResult.getCode()>= 400)? ExperimentDAO.Status.error: ExperimentDAO.Status.success); + experimentDAO.setResult((exaremeResult.getCode() >= 400) ? null : JsonConverters.convertObjectToJsonString(exaremeResult.getResults())); + experimentDAO.setStatus((exaremeResult.getCode() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); } catch (Exception e) { Logging.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "There was an exception: " + e.getMessage()); @@ -563,20 +548,19 @@ public class ExperimentService { /** * The runExaremeExperiment will run to exareme the experiment * - * @param url is the url that contain the results of the experiment - * @param body is the parameters of the algorithm + * @param url is the url that contain the results of the experiment + * @param body is the parameters of the algorithm * @param experimentDTO is the experiment information to be executed in the exareme * @return the result of exareme as well as the http status that was retrieved */ - public ExaremeResult runExaremeExperiment(String url,String body, ExperimentDTO experimentDTO) { + public ExaremeResult runExaremeExperiment(String url, String body, ExperimentDTO experimentDTO) { StringBuilder results = new StringBuilder(); int code; try { code = HTTPUtil.sendPost(url, body, results); - } - catch (Exception e){ - throw new InternalServerError("Error occurred : "+ e.getMessage()); + } catch (Exception e) { + throw new InternalServerError("Error occurred : " + e.getMessage()); } Logging.LogExperimentAction(experimentDTO.getName(), experimentDTO.getUuid(), "Algorithm finished with code: " + code); @@ -596,7 +580,7 @@ public class ExperimentService { * @return the response to be returned */ public ExperimentDTO runGalaxyWorkflow(ExperimentDTO experimentDTO, String endpoint) { - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); Logging.LogUserAction(user.getUsername(), endpoint, "Running a workflow..."); ExperimentDAO experimentDAO = createExperimentInTheDatabase(experimentDTO, endpoint); @@ -670,7 +654,7 @@ public class ExperimentService { JSONObject jObjectError = new JSONObject(msgErr); String errMsg = jObjectError.get("err_msg").toString(); - experimentDTO.setStatus((response.code()>= 400)? ExperimentDAO.Status.error: ExperimentDAO.Status.success); + experimentDTO.setStatus((response.code() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); } } catch (Exception e) { @@ -693,11 +677,11 @@ public class ExperimentService { * This method creates a thread that will fetch the workflow result when it is ready * * @param experimentDAO will be used to fetch it's workflow status, it should have the workflowHistoryId initialized - * and the result should not already be fetched + * and the result should not already be fetched * @return nothing, just updates the experiment */ public void updateWorkflowExperiment(ExperimentDAO experimentDAO, String endpoint) { - UserDAO user = userInfo.getUser(); + UserDAO user = activeUserService.getActiveUser(); if (experimentDAO == null) { Logging.LogUserAction(user.getUsername(), endpoint, "The experiment does not exist."); @@ -749,8 +733,7 @@ public class ExperimentService { Logging.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO: " + result); if (result == null) { experimentDAO.setStatus(ExperimentDAO.Status.error); - } - else { + } else { experimentDAO.setResult("[" + result + "]"); experimentDAO.setStatus(ExperimentDAO.Status.success); resultFound = true; @@ -908,7 +891,7 @@ public class ExperimentService { /** * @param experimentDAO The experiment of the workflow - * @param contentId the id of the job result that we want + * @param contentId the id of the job result that we want * @return the result of the specific workflow job, null if there was an error */ public String getWorkflowResultBody(ExperimentDAO experimentDAO, String contentId) { @@ -923,7 +906,7 @@ public class ExperimentService { Call<Object> call = service.getWorkflowResultsBodyFromGalaxy(historyId, contentId, galaxyApiKey); - String resultJson ; + String resultJson; try { Response<Object> response = call.execute(); if (response.code() >= 400) { diff --git a/src/main/java/eu/hbp/mip/services/ExperimentSpecifications.java b/src/main/java/eu/hbp/mip/services/ExperimentSpecifications.java index f59faa9ed73017bd9662f15a382fe1252925c2a4..45169c09d7d14594259745dc479ff39b1db4d599 100644 --- a/src/main/java/eu/hbp/mip/services/ExperimentSpecifications.java +++ b/src/main/java/eu/hbp/mip/services/ExperimentSpecifications.java @@ -1,6 +1,6 @@ package eu.hbp.mip.services; -import eu.hbp.mip.model.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.ExperimentDAO; import eu.hbp.mip.utils.Exceptions.BadRequestException; import org.springframework.data.jpa.domain.Specification; @@ -17,33 +17,31 @@ public class ExperimentSpecifications { private String name; private String regExp; - public ExperimentWithName(String name){ + public ExperimentWithName(String name) { this.name = name; this.regExp = name; } - public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) - { + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { if (name == null) { return cb.isTrue(cb.literal(true)); - } - else { - regExp = (name.contains("%")?name:name+"%"); + } else { + regExp = (name.contains("%") ? name : name + "%"); } - return cb.like( root.get( "name" ), this.regExp ); + return cb.like(root.get("name"), this.regExp); } } + public static class ExperimentWithAlgorithm implements Specification<ExperimentDAO> { private String algorithm; - public ExperimentWithAlgorithm(String algorithm){ + public ExperimentWithAlgorithm(String algorithm) { this.algorithm = algorithm; } - public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) - { + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { if (algorithm == null) { return cb.isTrue(cb.literal(true)); } @@ -56,7 +54,7 @@ public class ExperimentSpecifications { private Boolean viewed; - public ExperimentWithViewed(Boolean viewed){ + public ExperimentWithViewed(Boolean viewed) { this.viewed = viewed; } @@ -72,7 +70,7 @@ public class ExperimentSpecifications { private Boolean shared; - public ExperimentWithShared(Boolean shared){ + public ExperimentWithShared(Boolean shared) { this.shared = shared; } @@ -87,13 +85,14 @@ public class ExperimentSpecifications { public static class ExperimentOrderBy implements Specification<ExperimentDAO> { private String orderBy; - private Boolean descending ; - public ExperimentOrderBy(String orderBy, Boolean descending){ + private Boolean descending; + + public ExperimentOrderBy(String orderBy, Boolean descending) { if (properColumnToBeOrderedBy(orderBy)) this.orderBy = orderBy; else throw new BadRequestException("Please provide proper column to order by."); - if(descending == null) + if (descending == null) this.descending = true; else this.descending = descending; @@ -110,7 +109,7 @@ public class ExperimentSpecifications { } - public static boolean properColumnToBeOrderedBy(String column){ + public static boolean properColumnToBeOrderedBy(String column) { { List<String> properColumns = new ArrayList<>(); properColumns.add("uuid"); diff --git a/src/main/java/eu/hbp/mip/utils/CORSFilter.java b/src/main/java/eu/hbp/mip/utils/CORSFilter.java deleted file mode 100644 index 7ed1ecf38d84fedddb5acb4750db327fbb9e5079..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/utils/CORSFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -package eu.hbp.mip.utils; - -import javax.servlet.*; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * Created by mirco on 12.02.16. - */ -public class CORSFilter implements Filter { - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - HttpServletResponse response = (HttpServletResponse) res; - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader("Access-Control-Allow-Headers", "*"); - response.setHeader("Access-Control-Request-Headers", "*"); - chain.doFilter(req, res); - } - - @Override - public void init(FilterConfig filterConfig) { - /* Nothing to do */ - } - - @Override - public void destroy() { - /* Nothing to do */ - } -} diff --git a/src/main/java/eu/hbp/mip/utils/ClaimUtils.java b/src/main/java/eu/hbp/mip/utils/ClaimUtils.java index dea4cd0b5e898f385562a044749970108c592cfc..4e4f95c9d25620c07b8884709e691e56c6894927 100644 --- a/src/main/java/eu/hbp/mip/utils/ClaimUtils.java +++ b/src/main/java/eu/hbp/mip/utils/ClaimUtils.java @@ -1,7 +1,7 @@ package eu.hbp.mip.utils; import com.google.gson.Gson; -import eu.hbp.mip.model.DTOs.PathologyDTO; +import eu.hbp.mip.models.DTOs.PathologyDTO; import eu.hbp.mip.utils.Exceptions.BadRequestException; import org.springframework.security.core.GrantedAuthority; @@ -16,11 +16,11 @@ public class ClaimUtils { private static final Gson gson = new Gson(); public static String allDatasetsAllowedClaim() { - return "dataset_all"; + return "role_dataset_all"; } public static String getDatasetClaim(String datasetCode) { - return "dataset_" + datasetCode.toLowerCase(); + return "role_dataset_" + datasetCode.toLowerCase(); } public static void validateAccessRightsOnDatasets(String username, Collection<? extends GrantedAuthority> authorities, diff --git a/src/main/java/eu/hbp/mip/utils/CustomAccessDeniedHandler.java b/src/main/java/eu/hbp/mip/utils/CustomAccessDeniedHandler.java deleted file mode 100644 index 783e4a3ff68ab3384a798d9fc70f68f29c114bd6..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/utils/CustomAccessDeniedHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package eu.hbp.mip.utils; - -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.web.access.AccessDeniedHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.sql.Timestamp; - -public class CustomAccessDeniedHandler implements AccessDeniedHandler { - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, - AccessDeniedException accessDeniedException) throws IOException, ServletException { - response.setContentType("application/json;charset=UTF-8"); - response.setStatus(403); - try { - response.getWriter().write(new JSONObject() - .put("timestamp", new Timestamp(System.currentTimeMillis())) - .put("status", 403) - .put("error", "Forbidden") - .put("message", "Access Denied. Please contact the system administrator to request access.") - .put("path", request.getServletPath()) - .toString()); - } catch (JSONException e) { - response.getWriter().write(""); - e.printStackTrace(); - } - } -} diff --git a/src/main/java/eu/hbp/mip/utils/CustomLoginUrlAuthenticationEntryPoint.java b/src/main/java/eu/hbp/mip/utils/CustomLoginUrlAuthenticationEntryPoint.java deleted file mode 100644 index 45870c7778280ff60c8ccca2908105ee677a6f7a..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/utils/CustomLoginUrlAuthenticationEntryPoint.java +++ /dev/null @@ -1,21 +0,0 @@ -package eu.hbp.mip.utils; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -public class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { - - public CustomLoginUrlAuthenticationEntryPoint(String url) { - super(url); - } - - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1728999c2c96e9ad3dc9625a6145964ffaa91b21..30c82a447c62125c69a90159870e5a5fc8c6cc54 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,6 @@ -# Configuration template for the portal running inside a Docker container +# Configuration for development purposes -# See http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +### DATABASE CONFIGURATION ### spring: portal-datasource: url: "jdbc:postgresql://127.0.0.1:5433/portal" @@ -8,7 +8,6 @@ spring: username: "portal" password: "portalpwd" driver-class-name: org.postgresql.Driver - data: jpa: repositories: @@ -18,22 +17,7 @@ spring: dialect: org.hibernate.dialect.PostgreSQL9Dialect ddl-auto: validate -# HBP OAUTH2 LOGIN -hbp: - authentication: - enabled: 0 - client: - clientId: "MIP" - clientSecret: "dae83a6b-c769-4186-8383-f0984c6edf05" - logoutUri: http://127.0.0.1/auth/realms/MIP/protocol/openid-connect/logout - - -# WEB FRONTEND -frontend: - loginUrl: "http://127.0.0.1/services/login/hbp" - redirectAfterLoginUrl: "http://127.0.0.1/" - redirectAfterLogoutUrl: "http://127.0.0.1/services/login/hbp" - +### LOG LEVELS ### logging: level: root: "ERROR" @@ -41,16 +25,14 @@ logging: eu: hbp: "DEBUG" -# EMBEDDED SERVER CONFIGURATION +### EMBEDDED SERVER CONFIGURATION ### server: servlet: contextPath: "/services" port: 8080 forward-headers-strategy: native - session: - timeout: "2592000" -# ENDPOINTS +### ENDPOINTS ### endpoints: enabled: true health: @@ -58,12 +40,11 @@ endpoints: endpoint: "/health" sensitive: false -# External Services +### EXTERNAL SERVICES ### services: exareme: queryExaremeUrl: "http://127.0.0.1:9090/mining/query" algorithmsUrl: "http://127.0.0.1:9090/mining/algorithms.json" - galaxy: galaxyUrl: "http://127.0.0.1:8090" galaxyContext: "nativeGalaxy/workflows/list" @@ -71,11 +52,23 @@ services: galaxyUsername: "admin" galaxyPassword: "password" - keycloak: - keycloakUrl: "127.0.0.1" +### Authentication ### +authentication: + enabled: true - pathologies: - pathologiesUrl: "classPath:/pathologies.json" +### Keycloak ### +keycloak: + enabled: true + auth-server-url: "http://127.0.0.1/auth" + realm: "MIP" + resource: "MIP" + enable-basic-auth: true + credentials: + secret: "dae83a6b-c769-4186-8383-f0984c6edf05" + principal-attribute: "preferred_username" - algorithms: - disabledAlgorithmsUrl: "classPath:/disableAlgorithms.json" \ No newline at end of file +### EXTERNAL FILES ### +# Files are loaded from the resources +files: + pathologies_json: "classPath:/pathologies.json" + disabledAlgorithms_json: "classPath:/disabledAlgorithms.json"