Added basic authentication on api POST routes.

This commit is contained in:
neviyn 2018-10-08 11:42:13 +01:00
parent 72e8b095c8
commit 65070275a3
6 changed files with 146 additions and 58 deletions

View File

@ -39,6 +39,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.module</groupId> <groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId> <artifactId>jackson-module-kotlin</artifactId>

View File

@ -0,0 +1,72 @@
package uk.co.neviyn.observationdatabase
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Component
import java.io.IOException
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@Configuration
@EnableWebSecurity
class CustomWebSecurityConfigurerAdapter : WebSecurityConfigurerAdapter() {
@Autowired
lateinit var authenticationEntryPoint: MyBasicAuthenticationEntryPoint
@Autowired
@Throws(Exception::class)
fun configureGlobal(auth: AuthenticationManagerBuilder) {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("admin"))
.authorities("ROLE_USER")
}
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/**").authenticated()
.anyRequest().permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}
@Component
class MyBasicAuthenticationEntryPoint: BasicAuthenticationEntryPoint() {
@Throws(IOException::class, ServletException::class)
override fun commence
(request: HttpServletRequest, response: HttpServletResponse, authEx: AuthenticationException) {
response.addHeader("WWW-Authenticate", "Basic realm=\"$realmName\"")
response.status = HttpServletResponse.SC_UNAUTHORIZED
response.writer.println("HTTP Status 401 - " + authEx.message)
}
@Throws
override fun afterPropertiesSet() {
realmName = "Security"
super.afterPropertiesSet()
}
}

View File

@ -144,7 +144,7 @@ class ControllerTest {
val observation = Observation(1, site, LocalDate.now(), TrainingType.INITIAL, "An Observation", "Group A", 5.0, 5.0, 5.0, .05, 5.0, newData.entries, setOf(tutor)) val observation = Observation(1, site, LocalDate.now(), TrainingType.INITIAL, "An Observation", "Group A", 5.0, 5.0, 5.0, .05, 5.0, newData.entries, setOf(tutor))
doReturn(observation).`when`(observationRepository).save(ArgumentMatchers.any()) doReturn(observation).`when`(observationRepository).save(ArgumentMatchers.any())
val result = controller.addObservation(newData) val result = controller.addObservation(newData)
assertEquals(1, result) assertEquals(1L, result)
} }
} }

View File

@ -144,7 +144,7 @@
console.log("submit"); console.log("submit");
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
var form = document.getElementById("submission-form"); let form = document.getElementById("submission-form");
if (form.checkValidity()) { if (form.checkValidity()) {
this.$router.push("/observation"); this.$router.push("/observation");
} }

View File

@ -3,44 +3,56 @@
<h2>New Site</h2> <h2>New Site</h2>
<b-form @submit="onSubmit" id="submission-form"> <b-form @submit="onSubmit" id="submission-form">
<b-form-group horizontal label="Site Name"> <b-form-group horizontal label="Site Name">
<b-form-input v-model="siteName" type="text" style="text-align:center;" /> <b-form-input v-model="siteName" type="text" style="text-align:center;"/>
</b-form-group>
<b-form-group horizontal label="Password">
<b-form-input v-model="submissionPassword" type="password" style="text-align:center;" />
</b-form-group> </b-form-group>
<b-button type="submit" size="lg" variant="primary">Submit</b-button> <b-button type="submit" size="lg" variant="primary">Submit</b-button>
</b-form> </b-form>
<br /> <br/>
<b-alert :show="dismissCountDown" dismissible fade :variant="alertVariant" @dismissed="dismissCountDown=0" @dismiss-count-down="countDownChanged"> <b-alert :show="dismissCountDown" dismissible fade :variant="alertVariant" @dismissed="dismissCountDown=0"
@dismiss-count-down="countDownChanged">
{{ alertText }} {{ alertText }}
</b-alert> </b-alert>
</b-container> </b-container>
</template> </template>
<script> <script>
import Vue from "vue"; import Vue from "vue";
export default {
export default {
name: "newSite", name: "newSite",
data: function() { data: function () {
return { return {
siteName: null, siteName: null,
dismissSecs: 5, dismissSecs: 5,
dismissCountDown: 0, dismissCountDown: 0,
alertVariant: "info", alertVariant: "info",
alertText: "" alertText: "",
submissionPassword: ""
}; };
}, },
methods: { methods: {
countDownChanged: function(dismissCountDown) { countDownChanged: function (dismissCountDown) {
this.dismissCountDown = dismissCountDown; this.dismissCountDown = dismissCountDown;
}, },
showAlert: function() { showAlert: function () {
this.dismissCountDown = this.dismissSecs; this.dismissCountDown = this.dismissSecs;
}, },
onSubmit: function(e) { onSubmit: function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
var form = document.getElementById("submission-form"); var form = document.getElementById("submission-form");
let axiosConfig = {
auth: {
username: "admin",
password: this.submissionPassword
}
};
if (form.checkValidity()) { if (form.checkValidity()) {
Vue.axios Vue.axios
.post("/site", { 'name':this.siteName }) .post("/site", {'name': this.siteName}, axiosConfig)
.then(response => { .then(response => {
this.alertVariant = "success"; this.alertVariant = "success";
this.alertText = "Successfully added " + response.data.text; this.alertText = "Successfully added " + response.data.text;
@ -55,5 +67,5 @@ export default {
} }
} }
} }
}; };
</script> </script>

View File

@ -60,7 +60,7 @@ export default {
var form = document.getElementById("submission-form"); var form = document.getElementById("submission-form");
let axiosConfig = { let axiosConfig = {
auth: { auth: {
username: "test", username: "admin",
password: this.submissionPassword password: this.submissionPassword
} }
}; };
@ -69,7 +69,7 @@ export default {
.post("/tutor", { .post("/tutor", {
'siteId': this.siteSelection, 'siteId': this.siteSelection,
'name': this.tutorName 'name': this.tutorName
}) }, axiosConfig)
.then(response => { .then(response => {
this.alertVariant = "success"; this.alertVariant = "success";
this.alertText = "Successfully added " + response.data.text; this.alertText = "Successfully added " + response.data.text;
@ -80,7 +80,7 @@ export default {
this.alertText = "Failed to add Tutor"; this.alertText = "Failed to add Tutor";
this.showAlert(); this.showAlert();
console.log(error); console.log(error);
}, axiosConfig); });
} }
} }
} }