Skip to content

Commit

Permalink
Add JSON login back; remove submodule cloning being necessary, as we …
Browse files Browse the repository at this point in the history
…now use the git reference to material-table
  • Loading branch information
Ariel Guelfi committed Mar 20, 2024
1 parent be9a395 commit 3af6519
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 53 deletions.
15 changes: 0 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,6 @@ Installed below dependencies:
- Java 17
- NodeJS 18

# Cloning

This project uses the [material-table](https://github.com/databucket/material-table.git) project as a Git Submodule.
In order to be able to build the frontend, the submodule is also built.
Clone the project with the extra `--recurse-submodules` argument in order to also have the material-table code.

```shell
git clone --recurse-submodules https://github.com/databucket/databucket-server.git
```

If you need to update the material-table submodule, you can run:
```shell
git submodule update --recursive --remote
```

## Useful commands

| command | what it does |
Expand Down
2 changes: 1 addition & 1 deletion frontend/material-table
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
package pl.databucket.server.controller;

import io.swagger.annotations.Api;
import java.util.Arrays;
import java.util.Collections;
import javax.mail.MessagingException;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -21,9 +14,6 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import pl.databucket.server.configuration.AppProperties;
import pl.databucket.server.dto.ReCaptchaSiteVerifyResponseDTO;
import pl.databucket.server.exception.ExceptionFormatter;
import pl.databucket.server.exception.ForbiddenRepetitionException;
import pl.databucket.server.service.ManageUserService;
Expand All @@ -36,9 +26,7 @@
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class PublicController {

Logger logger = LoggerFactory.getLogger(PublicController.class);
ManageUserService manageUserService;
AppProperties appProperties;
private final ExceptionFormatter exceptionFormatter = new ExceptionFormatter(PublicController.class);


Expand Down Expand Up @@ -70,28 +58,5 @@ public ResponseEntity<?> signUpConfirmation(@PathVariable String jwts) {
}
}

private boolean checkReCaptcha(String token) {
RestTemplate restTemplate = new RestTemplate();

String uri = "https://www.google.com/recaptcha/api/siteverify" +
"?secret=" + appProperties.getRecaptchaSecretKey() +
"&response=" + token;

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
ResponseEntity<?> result = restTemplate.exchange(uri, HttpMethod.GET, entity,
ReCaptchaSiteVerifyResponseDTO.class);
ReCaptchaSiteVerifyResponseDTO reCaptchaSiteVerifyResponse = (ReCaptchaSiteVerifyResponseDTO) result.getBody();
assert reCaptchaSiteVerifyResponse != null;

if (!reCaptchaSiteVerifyResponse.isSuccess()) {
logger.error("ReCaptcha failed: " + Arrays.toString(reCaptchaSiteVerifyResponse.getErrorCodes()));
}

return reCaptchaSiteVerifyResponse.isSuccess() && reCaptchaSiteVerifyResponse.getScore() > 0.5;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import pl.databucket.server.dto.AuthRespDTO;

@Log4j2
Expand All @@ -22,10 +23,12 @@ public class BasicAuthSecurityConfig {
@Bean
public SecurityFilterChain basicSecurityFilterChain(HttpSecurity http,
AuthResponseBuilder authResponseBuilder,
JsonAuthenticationFilter jsonLoginFilter,
ObjectMapper mapper) throws Exception {
AuthenticationSuccessHandler successHandler = getFormSuccessHandler(authResponseBuilder);
AuthenticationFailureHandler failureHandler = getAuthenticationFailureHandler(mapper);
http.cors().and().csrf().disable()
.addFilterBefore(jsonLoginFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.GET,
"/", "/login**", "/sign-up", "/forgot-password", "/change-password",
Expand All @@ -52,7 +55,8 @@ public SecurityFilterChain basicSecurityFilterChain(HttpSecurity http,
return http.build();
}

private static AuthenticationFailureHandler getAuthenticationFailureHandler(ObjectMapper mapper) {
@Bean
public AuthenticationFailureHandler getAuthenticationFailureHandler(ObjectMapper mapper) {
return (request, response, exception) -> {
log.error("Auth error", exception);
AuthRespDTO authResponse = AuthRespDTO.builder().message(exception.getMessage()).build();
Expand All @@ -63,7 +67,8 @@ private static AuthenticationFailureHandler getAuthenticationFailureHandler(Obje
};
}

private AuthenticationSuccessHandler getFormSuccessHandler(AuthResponseBuilder authResponseBuilder) {
@Bean
public AuthenticationSuccessHandler getFormSuccessHandler(AuthResponseBuilder authResponseBuilder) {
return new FormAuthSuccessHandler(authResponseBuilder);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package pl.databucket.server.security;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

/**
* Allows for a POST JSON sigin in instead of the x-www-form-urlencoded version when calling POST /login-form
*/
@Component
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

private final ObjectMapper mapper;
/**
* We can't call request.getReader() twice, so we save the result of the first call in a ThreadLocal var as not to
* mix different requests.
*/
private static final ThreadLocal<Map<String, String>> ongoingAuth = new ThreadLocal<>();

public JsonAuthenticationFilter(ObjectMapper mapper, AuthenticationManager authenticationManager,
AuthenticationSuccessHandler successHandler) {
super(authenticationManager);
this.setAuthenticationSuccessHandler(successHandler);
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/public/sign-in",
"POST"));
this.mapper = mapper;
}

@Override
protected String obtainUsername(HttpServletRequest request) {
try {
Map<String, String> map = mapper.readValue(request.getReader(), new TypeReference<>() {
});
ongoingAuth.set(map);
return map.get(SPRING_SECURITY_FORM_USERNAME_KEY);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
protected String obtainPassword(HttpServletRequest request) {
return ongoingAuth.get().get(SPRING_SECURITY_FORM_PASSWORD_KEY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import pl.databucket.server.dto.AuthRespDTO;
import pl.databucket.server.repository.RoleRepository;
import pl.databucket.server.service.ManageUserService;
Expand All @@ -26,11 +27,13 @@ public class OAuth2SecurityConfig {
public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http,
OAuth2LogoutHandler oauth2LogoutHandler,
AuthResponseBuilder authResponseBuilder,
JsonAuthenticationFilter jsonLoginFilter,
ObjectMapper mapper,
AuthenticationSuccessHandler oAuth2SuccessHandler) throws Exception {
AuthenticationSuccessHandler successHandler = getFormSuccessHandler(authResponseBuilder);
AuthenticationFailureHandler failureHandler = getAuthenticationFailureHandler(mapper);
http.cors().and().csrf().disable()
.addFilterBefore(jsonLoginFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.GET,
"/", "/login**", "/sign-up", "/forgot-password", "/change-password",
Expand Down

0 comments on commit 3af6519

Please sign in to comment.