Implemented a simple Token Authentication for the /accounts endpoints, so not everyone can just create and delete accounts for fun. Closes #14
parent
333ee23c42
commit
f6e792b4e8
|
@ -50,7 +50,9 @@ public class AccountCrudTest {
|
||||||
@Test
|
@Test
|
||||||
void newAccountCanBeCreatedAndAccessedAfterwards() throws Exception {
|
void newAccountCanBeCreatedAndAccessedAfterwards() throws Exception {
|
||||||
AccountForm form = new AccountForm("my-company", List.of("vip@my-company.com"));
|
AccountForm form = new AccountForm("my-company", List.of("vip@my-company.com"));
|
||||||
mockMvc.perform(post("/accounts").contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
mockMvc.perform(post("/accounts").header("x-nclazz-auth", "integration-token")
|
||||||
|
.contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||||
|
|
||||||
.andExpect(status().isCreated())
|
.andExpect(status().isCreated())
|
||||||
.andExpect(content().contentType(APPLICATION_JSON))
|
.andExpect(content().contentType(APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultHandlers.print())
|
.andDo(MockMvcResultHandlers.print())
|
||||||
|
@ -64,7 +66,7 @@ public class AccountCrudTest {
|
||||||
Account account = Account.of("retrievable-account", List.of("info@account.com"));
|
Account account = Account.of("retrievable-account", List.of("info@account.com"));
|
||||||
account = relay.saveAccount(account);
|
account = relay.saveAccount(account);
|
||||||
|
|
||||||
mockMvc.perform(get("/accounts/{guid}", account.getGuid()))
|
mockMvc.perform(get("/accounts/{guid}", account.getGuid()).header("x-nclazz-auth", "integration-token"))
|
||||||
.andExpect(status().is2xxSuccessful())
|
.andExpect(status().is2xxSuccessful())
|
||||||
.andExpect(content().contentType(APPLICATION_JSON))
|
.andExpect(content().contentType(APPLICATION_JSON))
|
||||||
.andExpect(jsonPath("$.name").value("retrievable-account"))
|
.andExpect(jsonPath("$.name").value("retrievable-account"))
|
||||||
|
@ -79,7 +81,9 @@ public class AccountCrudTest {
|
||||||
|
|
||||||
AccountForm form = new AccountForm("updated-account-renamed", List.of("vip@account.com"));
|
AccountForm form = new AccountForm("updated-account-renamed", List.of("vip@account.com"));
|
||||||
|
|
||||||
mockMvc.perform(put("/accounts/{guid}", account.getGuid()).contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
mockMvc.perform(put("/accounts/{guid}", account.getGuid()).header("x-nclazz-auth", "integration-token")
|
||||||
|
.contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||||
|
|
||||||
.andExpect(status().is2xxSuccessful())
|
.andExpect(status().is2xxSuccessful())
|
||||||
.andExpect(content().contentType(APPLICATION_JSON))
|
.andExpect(content().contentType(APPLICATION_JSON))
|
||||||
.andExpect(jsonPath("$.name").value("updated-account-renamed"))
|
.andExpect(jsonPath("$.name").value("updated-account-renamed"))
|
||||||
|
@ -90,7 +94,9 @@ public class AccountCrudTest {
|
||||||
@Test
|
@Test
|
||||||
void createAccountReturns400OnInvalidName() throws Exception {
|
void createAccountReturns400OnInvalidName() throws Exception {
|
||||||
AccountForm form = new AccountForm("-- totally invalid --", List.of("vip@my-company.com"));
|
AccountForm form = new AccountForm("-- totally invalid --", List.of("vip@my-company.com"));
|
||||||
mockMvc.perform(post("/accounts").contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
mockMvc.perform(post("/accounts").header("x-nclazz-auth", "integration-token")
|
||||||
|
.contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||||
|
|
||||||
.andExpect(status().is4xxClientError())
|
.andExpect(status().is4xxClientError())
|
||||||
.andExpect(content().contentType(APPLICATION_JSON));
|
.andExpect(content().contentType(APPLICATION_JSON));
|
||||||
}
|
}
|
||||||
|
@ -98,8 +104,17 @@ public class AccountCrudTest {
|
||||||
@Test
|
@Test
|
||||||
void createAccountReturns400OnInvalidReceiver() throws Exception {
|
void createAccountReturns400OnInvalidReceiver() throws Exception {
|
||||||
AccountForm form = new AccountForm("valid-name", List.of("valid@my-company.com", "in valid @my-company.com"));
|
AccountForm form = new AccountForm("valid-name", List.of("valid@my-company.com", "in valid @my-company.com"));
|
||||||
mockMvc.perform(post("/accounts").contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
mockMvc.perform(post("/accounts").header("x-nclazz-auth", "integration-token")
|
||||||
|
|
||||||
|
.contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||||
.andExpect(status().is4xxClientError())
|
.andExpect(status().is4xxClientError())
|
||||||
.andExpect(content().contentType(APPLICATION_JSON));
|
.andExpect(content().contentType(APPLICATION_JSON));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenNoAuthTokenIsProvidedReturns401() throws Exception {
|
||||||
|
AccountForm form = new AccountForm("valid-name", List.of("valid@my-company.com", "in valid @my-company.com"));
|
||||||
|
mockMvc.perform(post("/accounts").contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||||
|
.andExpect(status().is(401));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,6 @@ spring.mail.username=springboot
|
||||||
spring.mail.password=integration
|
spring.mail.password=integration
|
||||||
spring.mail.host=localhost
|
spring.mail.host=localhost
|
||||||
spring.mail.port=25
|
spring.mail.port=25
|
||||||
spring.mail.protocol=smtp
|
spring.mail.protocol=smtp
|
||||||
|
|
||||||
|
nclazz.auth.token=integration-token
|
|
@ -1,7 +1,10 @@
|
||||||
package de.nclazz.service.mailrelay;
|
package de.nclazz.service.mailrelay;
|
||||||
|
|
||||||
|
import de.nclazz.service.mailrelay.adapter.web.SimpleAuthenticationFilter;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
|
@ -18,4 +21,14 @@ public class MailRelayApplication {
|
||||||
return Clock.systemDefaultZone();
|
return Clock.systemDefaultZone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean<SimpleAuthenticationFilter> simpleAuthenticationFilter(@Value("${nclazz.auth.token}") String authenticationToken){
|
||||||
|
FilterRegistrationBean<SimpleAuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
|
||||||
|
|
||||||
|
registrationBean.setFilter(new SimpleAuthenticationFilter(authenticationToken));
|
||||||
|
registrationBean.addUrlPatterns("/accounts/*");
|
||||||
|
|
||||||
|
return registrationBean;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,15 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("accounts")
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("accounts")
|
||||||
public class AccountRestController {
|
public class AccountRestController {
|
||||||
|
|
||||||
private final Relay relay;
|
private final Relay relay;
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<Account> addAccount(@RequestBody @Valid AccountForm form) {
|
public ResponseEntity<Account> addAccount(@RequestBody @Valid AccountForm form) {
|
||||||
|
|
||||||
Account account = form.toAccount();
|
Account account = form.toAccount();
|
||||||
account = this.relay.saveAccount(account);
|
account = this.relay.saveAccount(account);
|
||||||
return ResponseEntity.status(HttpStatus.CREATED).body(account);
|
return ResponseEntity.status(HttpStatus.CREATED).body(account);
|
||||||
|
@ -51,11 +52,13 @@ public class AccountRestController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("{guid}")
|
@PutMapping("{guid}")
|
||||||
public Account updateByGuid(@PathVariable("guid")UUID guid, @RequestBody @Valid AccountForm form) {
|
public Account updateByGuid(@PathVariable("guid")UUID guid,
|
||||||
|
@RequestBody @Valid AccountForm form) {
|
||||||
Account account = this.relay.findAccount(guid)
|
Account account = this.relay.findAccount(guid)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
||||||
account.setName(form.getName());
|
account.setName(form.getName());
|
||||||
account.setReceivers(form.getReceivers());
|
account.setReceivers(form.getReceivers());
|
||||||
return this.relay.saveAccount(account);
|
return this.relay.saveAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package de.nclazz.service.mailrelay.adapter.web;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SimpleAuthenticationFilter implements Filter {
|
||||||
|
|
||||||
|
private final String authenticationToken;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
HttpServletRequest req = (HttpServletRequest) servletRequest;
|
||||||
|
HttpServletResponse res = (HttpServletResponse) servletResponse;
|
||||||
|
|
||||||
|
String token = req.getHeader("x-nclazz-auth");
|
||||||
|
|
||||||
|
if(!this.authenticationToken.equals(token)) {
|
||||||
|
res.setStatus(401);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
# DDL auto schema generation (update, create, create-drop, none, validate)
|
# DDL auto schema generation (update, create, create-drop, none, validate)
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
spring.datasource.url=jdbc:h2:file:./test-db
|
spring.datasource.url=jdbc:h2:file:./test-db
|
||||||
|
|
||||||
|
nclazz.auth.token=
|
|
@ -16,7 +16,6 @@ class AccountRestControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void addAccountCreatesNewAccountAndReturnsIs() {
|
void addAccountCreatesNewAccountAndReturnsIs() {
|
||||||
|
|
||||||
Relay relay = TestRelayBuilder.builder().build();
|
Relay relay = TestRelayBuilder.builder().build();
|
||||||
|
|
||||||
AccountRestController controller = new AccountRestController(relay);
|
AccountRestController controller = new AccountRestController(relay);
|
||||||
|
@ -86,6 +85,7 @@ class AccountRestControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void accountCanBeUpdated() {
|
void accountCanBeUpdated() {
|
||||||
|
String authToken = "auth-token";
|
||||||
Relay relay = TestRelayBuilder.builder().build();
|
Relay relay = TestRelayBuilder.builder().build();
|
||||||
|
|
||||||
AccountRestController controller = new AccountRestController(relay);
|
AccountRestController controller = new AccountRestController(relay);
|
||||||
|
@ -103,4 +103,5 @@ class AccountRestControllerTest {
|
||||||
.extracting("name", "receivers")
|
.extracting("name", "receivers")
|
||||||
.containsExactly("my-renamed-account", List.of("vip@my-company.com", "other@my-company.com"));
|
.containsExactly("my-renamed-account", List.of("vip@my-company.com", "other@my-company.com"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue