diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java index 40f9c3f70ac2ec1c77409ced44fd82459e8b571c..e7684780cda97e9bd74f6869b5fcd248b6d009c3 100644 --- a/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java +++ b/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -82,7 +82,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /* set permissions on endpoints */ http.authorizeRequests() /* our public endpoints */ -// .antMatchers("/api/auth**").permitAll() .antMatchers(HttpMethod.POST, "/api/user").permitAll() .antMatchers(HttpMethod.POST, "/api/auth").permitAll() /* our private endpoints */ diff --git a/fda-container-service/rest-service/src/main/resources/application-docker.yml b/fda-container-service/rest-service/src/main/resources/application-docker.yml index 1035559b257db6a5c99e64ecdb250d6bba1c9443..b18fc742b2c1298fdf50cb17e31d7544382908ba 100644 --- a/fda-container-service/rest-service/src/main/resources/application-docker.yml +++ b/fda-container-service/rest-service/src/main/resources/application-docker.yml @@ -25,4 +25,5 @@ eureka: instance.hostname: fda-container-service client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ fda: - ready.path: /ready \ No newline at end of file + ready.path: /ready + auth.url: http://fda-authentication-service:9097/api/auth \ No newline at end of file diff --git a/fda-container-service/rest-service/src/main/resources/application.yml b/fda-container-service/rest-service/src/main/resources/application.yml index 94399f1b0fc380082d66ec1f458880b10b37ad57..98f135bd1e153208b9a61c9023f2036a6db80c09 100644 --- a/fda-container-service/rest-service/src/main/resources/application.yml +++ b/fda-container-service/rest-service/src/main/resources/application.yml @@ -25,4 +25,5 @@ eureka: instance.hostname: fda-container-service client.serviceUrl.defaultZone: http://localhost:9090/eureka/ fda: - ready.path: ./ready \ No newline at end of file + ready.path: ./ready + auth.url: http://localhost:9097/api/auth \ No newline at end of file diff --git a/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..9832234740ead10f80163b75958b5363a7789cd5 --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -0,0 +1,67 @@ +package at.tuwien.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.http.HttpServletResponse; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Value("${fda.auth.url}") + private String authUrl; + + @Override + protected void configure(HttpSecurity http) throws Exception { + /* enable CORS and disable CSRF */ + http = http.cors().and().csrf().disable(); + /* set session management to stateless */ + http = http + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and(); + /* set unauthorized requests exception handler */ + http = http + .exceptionHandling() + .authenticationEntryPoint( + (request, response, ex) -> { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, + ex.getMessage() + ); + } + ).and(); + /* set permissions on endpoints */ + http.authorizeRequests() + /* our private endpoints */ + .anyRequest().authenticated(); + /* set auth url */ + http.formLogin() + .loginProcessingUrl(authUrl); + } + + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/exception/AuthenticationException.java b/fda-container-service/services/src/main/java/at/tuwien/exception/AuthenticationException.java new file mode 100644 index 0000000000000000000000000000000000000000..1984387d1e7789ffc6076bd3717514360c7eebfd --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/exception/AuthenticationException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.FORBIDDEN, reason = "Persistence error") +public class AuthenticationException extends Exception { + + public AuthenticationException(String msg) { + super(msg); + } + + public AuthenticationException(String msg, Throwable thr) { + super(msg, thr); + } + + public AuthenticationException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java index d5afe7b847bc22decae63e46c3aa142e8af0256e..3662f91b11d206a5834babdba82fe5b59c3372b2 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java +++ b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java @@ -70,7 +70,7 @@ public class ContainerServiceImpl implements ContainerService { container.setPort(availableTcpPort); container.setName(createDto.getName()); container.setInternalName(containerMapper.containerToInternalContainerName(container)); - log.debug("will create host config {} and container {}", hostConfig, container); + log.trace("will create host config {} and container {}", hostConfig, container); /* create the container */ final CreateContainerResponse response; try { @@ -81,8 +81,12 @@ public class ContainerServiceImpl implements ContainerService { .withHostConfig(hostConfig) .exec(); } catch (ConflictException e) { - log.error("conflicting names for container {}, reason: {}", createDto, e.getMessage()); + log.error("Conflicting names {}", createDto.getName()); throw new DockerClientException("Unexpected behavior", e); + } catch (NotFoundException e) { + log.error("The image {}:{} not available on the container service", createDto.getRepository(), createDto.getTag()); + log.debug("payload was {}", createDto); + throw new DockerClientException("Image not available", e); } container.setHash(response.getId()); container = containerRepository.save(container); diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue index fffa3f62a15aa101d1d9a02dfc1003ab08aef37c..b92bb74530348900293fd5d50f3b62173d23d44e 100644 --- a/fda-ui/layouts/default.vue +++ b/fda-ui/layouts/default.vue @@ -31,7 +31,7 @@ <v-btn class="mr-2 white--text" color="blue-grey" - @click="loginDialog = true"> + to="/login"> <v-icon left>mdi-login</v-icon> Login </v-btn> <v-menu bottom offset-y left> @@ -44,7 +44,7 @@ </v-btn> </template> <v-list> - <v-list-item @click="registerDialog = true"> + <v-list-item to="/signup"> <v-list-item-icon> <v-icon left>mdi-account-plus</v-icon> </v-list-item-icon> @@ -79,18 +79,6 @@ </v-card-text> </v-card> </v-footer> - <v-dialog - v-model="loginDialog" - persistent - max-width="640"> - <Login @close="loginDialog = false" /> - </v-dialog> - <v-dialog - v-model="registerDialog" - persistent - max-width="640"> - <Register @close="registerDialog = false" /> - </v-dialog> </v-app> </template> @@ -104,20 +92,12 @@ import { mdiNewspaperVariantOutline, mdiCog } from '@mdi/js' -import Login from '../components/dialogs/Login' -import Register from '../components/dialogs/Register' export default { name: 'DefaultLayout', - components: { - Login, - Register - }, data () { return { drawer: false, - loginDialog: null, - registerDialog: null, items: [ { icon: mdiHome, diff --git a/fda-ui/pages/container/index.vue b/fda-ui/pages/container/index.vue index e28e6c5ffd5a28c8307942f57bc99794a583a15c..fe106920f7622f9946aa3eef48a61c2ab23680fb 100644 --- a/fda-ui/pages/container/index.vue +++ b/fda-ui/pages/container/index.vue @@ -76,6 +76,9 @@ export default { computed: { loadingColor () { return this.error ? 'red lighten-2' : 'primary' + }, + token () { + return this.$store.state.token } }, mounted () { @@ -86,7 +89,9 @@ export default { this.createDbDialog = false try { this.loading = true - let res = await this.$axios.get('/api/container/') + let res = await this.$axios.get('/api/container/', { + headers: { Authorization: `Bearer ${this.token}` } + }) this.containers = res.data console.debug('containers', this.containers) for (const container of this.containers) { diff --git a/fda-ui/components/dialogs/Login.vue b/fda-ui/pages/login.vue similarity index 90% rename from fda-ui/components/dialogs/Login.vue rename to fda-ui/pages/login.vue index 93c47b7c22729c8bc951a83f3183332c311a88b9..2de5fb7c1404e7f8af7835e7ef40c7d58cd11014 100644 --- a/fda-ui/components/dialogs/Login.vue +++ b/fda-ui/pages/login.vue @@ -30,11 +30,6 @@ </v-card-text> <v-card-actions> <v-spacer /> - <v-btn - class="mb-2" - @click="cancel"> - Cancel - </v-btn> <v-btn id="login" class="mb-2" @@ -69,17 +64,14 @@ export default { beforeMount () { }, methods: { - cancel () { - this.$parent.$parent.$parent.$parent.loginDialog = false - }, async login () { const url = '/api/auth' try { this.loading = true const res = await this.$axios.post(url, this.loginAccount) console.debug('login user', res.data) + this.$store.commit('SET_TOKEN', res.data.token) this.$toast.success('Welcome back!') - this.cancel() } catch (err) { console.error('login user failed', err) this.$toast.error('Failed to login user') diff --git a/fda-ui/components/dialogs/Register.vue b/fda-ui/pages/signup.vue similarity index 96% rename from fda-ui/components/dialogs/Register.vue rename to fda-ui/pages/signup.vue index aac81b13111d1eb3ff53e366119bb7c2bce8ebec..8eecba91341c5f82bf1317ccedb699a00de6aa12 100644 --- a/fda-ui/components/dialogs/Register.vue +++ b/fda-ui/pages/signup.vue @@ -101,9 +101,6 @@ export default { beforeMount () { }, methods: { - cancel () { - this.$parent.$parent.$parent.$parent.registerDialog = false - }, async register () { const url = '/api/user' try { @@ -111,7 +108,6 @@ export default { const res = await this.$axios.post(url, this.createAccount) console.debug('create user', res.data) this.$toast.success('Success. Check your inbox!') - this.cancel() } catch (err) { console.error('create user failed', err) this.$toast.error('Failed to create user') diff --git a/fda-ui/store/index.js b/fda-ui/store/index.js index b9ae5e2b05744db9b91b6fcdab707f28b05ab1c7..a362fb6a487ad4ab263ca92892d7f50ba9ed0574 100644 --- a/fda-ui/store/index.js +++ b/fda-ui/store/index.js @@ -1,12 +1,13 @@ export const state = () => ({ - db: null + db: null, + token: null }) export const mutations = { SET_DATABASE (state, db) { state.db = db }, - SET_THEME (state, theme) { - state.theme = theme + SET_TOKEN (state, token) { + state.token = token } }