Skip to content
Snippets Groups Projects
Commit 95c21a2d authored by Dominika Zemanovičová's avatar Dominika Zemanovičová
Browse files

Merge branch 'Confidential-Client-Fix' into 'main'

fixed ConfidentialClientApplication

See merge request !44
parents ac222b07 10119ca3
No related branches found
No related tags found
1 merge request!44fixed ConfidentialClientApplication
Pipeline #
Showing
with 201 additions and 84 deletions
FROM docker.io/library/eclipse-temurin:17-jre-focal
COPY ./target/confidentialClient-0.0.1-SNAPSHOT.jar /app.jar
ENV DOCKER_RUNNING=true
ENTRYPOINT ["java", "-jar", "/app.jar"]
\ No newline at end of file
package org.fuseri.confidentialclient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AuthClient {
@GetMapping("/token")
public String getToken( @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oauth2Client) {
return oauth2Client.getAccessToken().getTokenValue();
}
}
package org.fuseri.confidentialclient;
import org.fuseri.model.dto.user.UserCreateDto;
import org.fuseri.model.dto.user.UserDto;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
@RestController
public class AuthClientController {
@GetMapping("/token")
public String getToken(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oauth2Client) {
return oauth2Client.getAccessToken().getTokenValue();
}
@GetMapping("/register")
public String register(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oauth2Client, @AuthenticationPrincipal OidcUser user) {
var createDto = new UserCreateDto();
createDto.setLastName(user.getFamilyName());
createDto.setFirstName(user.getGivenName());
createDto.setEmail(user.getSubject()); // MUNI includes as subject user email
createDto.setUsername(user.getPreferredUsername());
// add access token to API call
OAuth2AccessToken accessToken = oauth2Client.getAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(accessToken.getTokenValue());
HttpEntity<UserCreateDto> request = new HttpEntity<>(createDto, headers);
String url = buildRegisterUrl();
RestTemplate userRegisterRestTemplate = new RestTemplate();
try {
var response = userRegisterRestTemplate.postForObject(url, request, UserDto.class);
return response == null ? "Unable to register user." : response.toString();
} catch (RestClientException e) {
return "Unable to register user: " + e.getMessage();
}
}
private static String buildRegisterUrl() {
String host;
if (!Boolean.parseBoolean(System.getenv("DOCKER_RUNNING")))
host = "localhost";
else host = switch (System.getProperty("os.name")) {
case "mac os x" -> "docker.for.mac.localhost";
case "windows" -> "host.docker.internal";
default -> "language-school"; // linux and others
};
return "http://" + host + ":8081/users/register";
}
}
package org.fuseri.confidentialclient;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.fuseri.model.dto.user.UserCreateDto;
import org.fuseri.model.dto.user.UserDto;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import java.io.IOException;
@SpringBootApplication
public class ConfidentialClientApplication {
......@@ -30,10 +13,6 @@ public class ConfidentialClientApplication {
SpringApplication.run(ConfidentialClientApplication.class, args);
}
private static String asJsonString(final Object obj) throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(obj);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
......@@ -43,47 +22,9 @@ public class ConfidentialClientApplication {
// all other requests must be authenticated
.anyRequest().authenticated()
)
.oauth2Login(x -> x
// our custom handler for successful logins
.successHandler(authenticationSuccessHandler())
)
.oauth2Login()
;
return httpSecurity.build();
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new SavedRequestAwareAuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res, Authentication auth) throws ServletException, IOException {
var a= res.getHeaderNames();
for (var name : a) {
System.out.println(res.getHeader(name));
}
System.out.println("got here");
if (auth instanceof OAuth2AuthenticationToken token
&& token.getPrincipal() instanceof OidcUser user) {
var createDto = new UserCreateDto();
createDto.setLastName(user.getFamilyName());
createDto.setFirstName(user.getGivenName());
createDto.setEmail(user.getEmail());
createDto.setUsername(user.getPreferredUsername());
//var result = WebClient.builder().baseUrl("http://localhost:8081/users/register").build().post()
//.contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(createDto))
//.retrieve();
//var out = result.bodyToMono(UserDto.class).block();
//System.out.println(out);
}
super.onAuthenticationSuccess(req, res, auth);
}
};
}
}
......@@ -10,6 +10,8 @@ services:
image: xpokorn8/sprachschulsystem:certificate
ports:
- "8082:8082"
environment:
- DOCKER_RUNNING=true
exercise:
build: ./module-exercise
......@@ -17,6 +19,8 @@ services:
image: xpokorn8/sprachschulsystem:exercise
ports:
- "8083:8083"
environment:
- DOCKER_RUNNING=true
language-school:
build: ./module-language-school
......@@ -24,6 +28,8 @@ services:
image: xpokorn8/sprachschulsystem:language-school
ports:
- "8081:8081"
environment:
- DOCKER_RUNNING=true
mail:
build: ./module-mail
......@@ -31,11 +37,15 @@ services:
image: xpokorn8/sprachschulsystem:mail
ports:
- "8084:8084"
environment:
- DOCKER_RUNNING=true
confidential-client:
build: ./confidentialClient
container_name: confidential-client
image: xpokorn8/sprachschulsystem:confidential-client
environment:
- DOCKER_RUNNING=true
ports:
- "8080:8080"
......@@ -45,6 +55,8 @@ services:
volumes:
- ./prometheus:/etc/prometheus
- prometheus_data:/prometheus
environment:
- DOCKER_RUNNING=true
expose:
- 9090
ports:
......@@ -56,6 +68,8 @@ services:
image: grafana/grafana:7.5.7
ports:
- "3000:3000"
environment:
- DOCKER_RUNNING=true
restart: unless-stopped
volumes:
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
......
......@@ -26,6 +26,7 @@ import java.util.Map;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
@ToString
@NoArgsConstructor
public class UserDto extends DomainObjectDto {
......
FROM docker.io/library/eclipse-temurin:17-jre-focal
COPY ./target/module-certificate-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
ENV DOCKER_RUNNING=true
ENTRYPOINT ["java", "-jar", "/app.jar"]
\ No newline at end of file
......@@ -7,7 +7,6 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.util.UrlPathHelper;
......@@ -41,7 +40,7 @@ public class RestResponseEntityExceptionHandler {
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public ResponseEntity<ApiError> handleValidationErrors(MethodArgumentNotValidException ex, HttpServletRequest request) {
List<ApiSubError> subErrors = ex.getBindingResult().getFieldErrors()
.stream()
......@@ -55,6 +54,22 @@ public class RestResponseEntityExceptionHandler {
return buildResponseEntity(error);
}
/**
* Handle MessageNotReadable exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {HttpMessageNotReadableException.class})
public ResponseEntity<ApiError> handleMessageNotReadableErrors(HttpMessageNotReadableException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle exceptions not matched by above handler methods
*
......
FROM docker.io/library/eclipse-temurin:17-jre-focal
COPY ./target/module-exercise-0.0.1-SNAPSHOT.jar /app.jar
ENV DOCKER_RUNNING=true
ENTRYPOINT ["java", "-jar", "/app.jar"]
......@@ -40,7 +40,7 @@ public class RestResponseEntityExceptionHandler {
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public ResponseEntity<ApiError> handleValidationErrors(MethodArgumentNotValidException ex, HttpServletRequest request) {
List<ApiSubError> subErrors = ex.getBindingResult().getFieldErrors()
.stream()
......@@ -54,6 +54,22 @@ public class RestResponseEntityExceptionHandler {
return buildResponseEntity(error);
}
/**
* Handle MessageNotReadable exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {HttpMessageNotReadableException.class})
public ResponseEntity<ApiError> handleMessageNotReadableErrors(HttpMessageNotReadableException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle exceptions not matched by above handler methods
*
......
FROM docker.io/library/eclipse-temurin:17-jre-focal
COPY ./target/module-language-school-0.0.1-SNAPSHOT.jar /app.jar
ENV DOCKER_RUNNING=true
ENTRYPOINT ["java", "-jar", "/app.jar"]
package org.fuseri.modulelanguageschool.exceptions;
public class EmailMismatchException extends RuntimeException {
public EmailMismatchException() {
}
public EmailMismatchException(String message) {
super(message);
}
}
......@@ -42,7 +42,7 @@ public class RestResponseEntityExceptionHandler {
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {UserWithEmailAlreadyExists.class, MissingServletRequestParameterException.class})
@ExceptionHandler(value = {UserWithEmailAlreadyExists.class})
public ResponseEntity<ApiError> handleUserWithEmailAlreadyExistsError(UserWithEmailAlreadyExists ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
......@@ -51,6 +51,38 @@ public class RestResponseEntityExceptionHandler {
return buildResponseEntity(error);
}
/**
* Handle EmailMismatchException exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {EmailMismatchException.class})
public ResponseEntity<ApiError> handleEmailMismatchError(EmailMismatchException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle MissingServletRequestParameterException exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {MissingServletRequestParameterException.class})
public ResponseEntity<ApiError> handleMissingRequestParameterException(MissingServletRequestParameterException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle Validation exceptions
*
......@@ -58,7 +90,7 @@ public class RestResponseEntityExceptionHandler {
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public ResponseEntity<ApiError> handleValidationErrors(MethodArgumentNotValidException ex, HttpServletRequest request) {
List<ApiSubError> subErrors = ex.getBindingResult().getFieldErrors()
.stream()
......@@ -72,6 +104,22 @@ public class RestResponseEntityExceptionHandler {
return buildResponseEntity(error);
}
/**
* Handle MessageNotReadable exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {HttpMessageNotReadableException.class})
public ResponseEntity<ApiError> handleMessageNotReadableErrors(HttpMessageNotReadableException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle exceptions not matched by above handler methods
*
......
......@@ -15,13 +15,25 @@ import org.fuseri.model.dto.user.UserAddLanguageDto;
import org.fuseri.model.dto.user.UserCreateDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.modulelanguageschool.ModuleLanguageSchoolApplication;
import org.fuseri.modulelanguageschool.exceptions.EmailMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Objects;
@RestController
@RequestMapping("/users")
......@@ -103,9 +115,16 @@ public class UserController {
}
@Operation(summary = "Registers a new user", description = "saves a new user into the database.")
@Operation(security = @SecurityRequirement(name = ModuleLanguageSchoolApplication.SECURITY_SCHEME_NAME, scopes = {}),
summary = "Registers a new user after oath login", description = "Saves a new user into the database after oath login.")
@PostMapping("/register")
public ResponseEntity<UserDto> register(@RequestBody @Valid UserCreateDto dto) {
public ResponseEntity<UserDto> register(@RequestBody @Valid UserCreateDto dto,
@AuthenticationPrincipal OAuth2IntrospectionAuthenticatedPrincipal principal) {
if (!Objects.equals(principal.getSubject(), dto.getEmail())) {
throw new EmailMismatchException(
String.format("Token email %s and body email %s does not match.", principal.getSubject(), dto.getEmail()));
}
UserDto user = facade.register(dto);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
......
FROM docker.io/library/eclipse-temurin:17-jre-focal
COPY ./target/module-mail-0.0.1-SNAPSHOT.jar /app.jar
ENV DOCKER_RUNNING=true
ENTRYPOINT ["java", "-jar", "/app.jar"]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment