Compare commits
2 Commits
main
...
feature_cr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
015157bce6 | ||
|
|
fe1e7b138e |
@ -1,105 +0,0 @@
|
|||||||
name: CI/CD Pipeline for Spring Boot
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# Step 1: Checkout code
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Step 2: Set up JDK
|
|
||||||
- name: Set up JDK 23
|
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
java-version: 23
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
# Step 3: Cache Maven dependencies
|
|
||||||
- name: Cache Maven Dependencies
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ~/.m2
|
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-maven-
|
|
||||||
|
|
||||||
# Step 4: Build and test
|
|
||||||
- name: Build and Test
|
|
||||||
run: |
|
|
||||||
./mvnw clean verify
|
|
||||||
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [ build-and-test ]
|
|
||||||
steps:
|
|
||||||
- name: Install Docker
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y docker.io
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Download buildx
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.docker/cli-plugins
|
|
||||||
curl -sL https://github.com/docker/buildx/releases/download/v0.11.2/buildx-v0.11.2.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
|
|
||||||
chmod +x ~/.docker/cli-plugins/docker-buildx
|
|
||||||
|
|
||||||
- name: Setup buildx
|
|
||||||
run: |
|
|
||||||
docker buildx create --use
|
|
||||||
docker buildx inspect --bootstrap
|
|
||||||
|
|
||||||
- name: Login to Cloud Coding Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: rg.fr-par.scw.cloud/weworkstudio
|
|
||||||
username: nologin
|
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@master
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:prod
|
|
||||||
build-args: |
|
|
||||||
XPEDITIS_PROFILE=prod
|
|
||||||
|
|
||||||
- name: Cleanup buildx
|
|
||||||
run: |
|
|
||||||
docker buildx rm
|
|
||||||
|
|
||||||
- name: Docker cleanup
|
|
||||||
run: docker system prune -af
|
|
||||||
|
|
||||||
- name: Uninstall Docker
|
|
||||||
run: |
|
|
||||||
apt-get purge -y docker.io
|
|
||||||
apt-get autoremove -y --purge docker.io
|
|
||||||
rm -rf /var/lib/docker /etc/docker
|
|
||||||
|
|
||||||
deploy_server:
|
|
||||||
name: Deploy - Docker - serveur
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [ docker ]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Déclencher le Webhook
|
|
||||||
run: |
|
|
||||||
curl -X POST -H "Content-Type:application/json" -d '{"data": "example" }' ${{ secrets.WEBHOOK_URL }}
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
name: CI/CD Pipeline for Spring Boot Dev
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# Step 1: Checkout code
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Step 2: Set up JDK
|
|
||||||
- name: Set up JDK 23
|
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
java-version: 23
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
# Step 3: Cache Maven dependencies
|
|
||||||
- name: Cache Maven Dependencies
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ~/.m2
|
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-maven-
|
|
||||||
|
|
||||||
# Step 4: Build and test
|
|
||||||
- name: Build and Test
|
|
||||||
run: |
|
|
||||||
./mvnw clean verify
|
|
||||||
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [ build-and-test ]
|
|
||||||
steps:
|
|
||||||
- name: Install Docker
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y docker.io
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Download buildx
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.docker/cli-plugins
|
|
||||||
curl -sL https://github.com/docker/buildx/releases/download/v0.11.2/buildx-v0.11.2.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
|
|
||||||
chmod +x ~/.docker/cli-plugins/docker-buildx
|
|
||||||
|
|
||||||
- name: Setup buildx
|
|
||||||
run: |
|
|
||||||
docker buildx create --use
|
|
||||||
docker buildx inspect --bootstrap
|
|
||||||
|
|
||||||
- name: Login to Cloud Coding Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: rg.fr-par.scw.cloud/weworkstudio
|
|
||||||
username: nologin
|
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@master
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:dev
|
|
||||||
build-args: |
|
|
||||||
XPEDITIS_PROFILE=dev
|
|
||||||
|
|
||||||
- name: Cleanup buildx
|
|
||||||
run: |
|
|
||||||
docker buildx rm
|
|
||||||
|
|
||||||
- name: Docker cleanup
|
|
||||||
run: docker system prune -af
|
|
||||||
|
|
||||||
- name: Uninstall Docker
|
|
||||||
run: |
|
|
||||||
apt-get purge -y docker.io
|
|
||||||
apt-get autoremove -y --purge docker.io
|
|
||||||
rm -rf /var/lib/docker /etc/docker
|
|
||||||
@ -11,6 +11,8 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||||
|
|
||||||
@ -33,4 +35,11 @@ public class AuthenticationRestController {
|
|||||||
@RequestBody @Valid RegisterRequest request) {
|
@RequestBody @Valid RegisterRequest request) {
|
||||||
return ResponseEntity.ok(service.register(request));
|
return ResponseEntity.ok(service.register(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optional: simple endpoint to start OAuth2 authorization if frontend needs a redirect URL
|
||||||
|
@GetMapping("/oauth2/authorization")
|
||||||
|
public ResponseEntity<Void> oauth2Authorization(@RequestParam("provider") String provider) {
|
||||||
|
// Frontend should redirect to /oauth2/authorization/{provider}
|
||||||
|
return ResponseEntity.status(302).header("Location", "/oauth2/authorization/" + provider).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.dh7789dev.xpeditis.controller.api.v1;
|
|||||||
|
|
||||||
import com.dh7789dev.xpeditis.UserService;
|
import com.dh7789dev.xpeditis.UserService;
|
||||||
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.UserAccount;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -10,8 +11,14 @@ import org.springframework.web.bind.annotation.PatchMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||||
|
|
||||||
@ -35,4 +42,35 @@ public class UserRestController {
|
|||||||
service.changePassword(request, connectedUser);
|
service.changePassword(request, connectedUser);
|
||||||
return new ResponseEntity<>(HttpStatus.OK);
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Create a user")
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<UserAccount> create(@RequestBody UserAccount user) {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(service.create(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Update a user")
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResponseEntity<UserAccount> update(@PathVariable Long id, @RequestBody UserAccount user) {
|
||||||
|
return ResponseEntity.ok(service.update(id, user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Get a user by id")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity<UserAccount> getById(@PathVariable Long id) {
|
||||||
|
return ResponseEntity.ok(service.getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "List users")
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<List<UserAccount>> list() {
|
||||||
|
return ResponseEntity.ok(service.list());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Delete a user")
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity<Void> delete(@PathVariable Long id) {
|
||||||
|
service.delete(id);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
package com.dh7789dev.xpeditis.configuration;
|
||||||
|
|
||||||
|
import com.dh7789dev.xpeditis.dao.UserDao;
|
||||||
|
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||||
|
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
|
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
||||||
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
|
||||||
|
|
||||||
|
private final UserDao userDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
|
||||||
|
OAuth2User oAuth2User = super.loadUser(userRequest);
|
||||||
|
|
||||||
|
Map<String, Object> attributes = oAuth2User.getAttributes();
|
||||||
|
String registrationId = userRequest.getClientRegistration().getRegistrationId();
|
||||||
|
|
||||||
|
String email;
|
||||||
|
if ("google".equals(registrationId)) {
|
||||||
|
email = (String) attributes.get("email");
|
||||||
|
} else if ("linkedin".equals(registrationId)) {
|
||||||
|
email = (String) attributes.getOrDefault("email", attributes.get("emailAddress"));
|
||||||
|
} else {
|
||||||
|
throw new OAuth2AuthenticationException("Unsupported provider: " + registrationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (email == null) {
|
||||||
|
throw new OAuth2AuthenticationException("Email not provided by OAuth2 provider.");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserEntity user = userDao.findByEmail(email)
|
||||||
|
.orElseThrow(() -> new UsernameNotFoundException("No local user bound to email: " + email));
|
||||||
|
|
||||||
|
return new DefaultOAuth2User(user.getAuthorities(), attributes, "email");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -88,8 +88,8 @@ public class GlobalConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public UserDetailsService userDetailsService() {
|
public UserDetailsService userDetailsService() {
|
||||||
return username -> userDao.findByUsername(username)
|
return identifier -> userDao.findByUsernameOrEmail(identifier)
|
||||||
.orElseThrow(() -> new UsernameNotFoundException(String.format(USER_NOT_FOUND_MSG, username)));
|
.orElseThrow(() -> new UsernameNotFoundException(String.format(USER_NOT_FOUND_MSG, identifier)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
final String jwt;
|
final String jwt;
|
||||||
final String username;
|
final String username;
|
||||||
|
|
||||||
if (request.getServletPath().contains("/api/v1/auth")) {
|
if (request.getServletPath().contains("/api/v1/auth") ||
|
||||||
|
request.getServletPath().startsWith("/oauth2/") ||
|
||||||
|
request.getServletPath().startsWith("/login/oauth2/")) {
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.dh7789dev.xpeditis.configuration;
|
||||||
|
|
||||||
|
import com.dh7789dev.xpeditis.dao.TokenDao;
|
||||||
|
import com.dh7789dev.xpeditis.dao.UserDao;
|
||||||
|
import com.dh7789dev.xpeditis.entity.TokenEntity;
|
||||||
|
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||||
|
import com.dh7789dev.xpeditis.util.JwtUtil;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OAuth2AuthenticationSuccessHandler implements AuthenticationSuccessHandler {
|
||||||
|
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final TokenDao tokenDao;
|
||||||
|
private final JwtUtil jwtUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||||
|
String email = authentication.getName();
|
||||||
|
UserEntity user = userDao.findByEmail(email)
|
||||||
|
.orElseThrow(() -> new UsernameNotFoundException("User not found for email: " + email));
|
||||||
|
|
||||||
|
String accessToken = jwtUtil.generateToken(user);
|
||||||
|
String refreshToken = jwtUtil.generateRefreshToken(user);
|
||||||
|
|
||||||
|
// Save token (like classic login)
|
||||||
|
TokenEntity tokenEntity = new TokenEntity()
|
||||||
|
.setUser(user)
|
||||||
|
.setToken(accessToken)
|
||||||
|
.setTokenType(TokenEntity.Type.BEARER)
|
||||||
|
.setExpired(false)
|
||||||
|
.setRevoked(false);
|
||||||
|
tokenDao.save(tokenEntity);
|
||||||
|
|
||||||
|
response.setContentType("application/json");
|
||||||
|
response.getWriter().write("{\"access_token\":\"" + accessToken + "\", \"refresh_token\":\"" + refreshToken + "\"}");
|
||||||
|
response.getWriter().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -34,13 +34,15 @@ public class SecurityConfiguration {
|
|||||||
boolean csrfEnabled;
|
boolean csrfEnabled;
|
||||||
|
|
||||||
private static final String ADMIN_ROLE = "ADMIN";
|
private static final String ADMIN_ROLE = "ADMIN";
|
||||||
private static final String ADMIN_PLATFORM_ROLE = "ADMIN_PLATFORM";
|
// private static final String ADMIN_PLATFORM_ROLE = "ADMIN_PLATFORM";
|
||||||
|
|
||||||
private static final String API_V1_URI = "/api/v1/**";
|
private static final String API_V1_URI = "/api/v1/**";
|
||||||
|
|
||||||
private static final String[] WHITE_LIST_URL = {
|
private static final String[] WHITE_LIST_URL = {
|
||||||
"/api/v1/auth/**",
|
"/api/v1/auth/**",
|
||||||
"/actuator/health/**"};
|
"/actuator/health/**",
|
||||||
|
"/oauth2/**",
|
||||||
|
"/login/oauth2/**"};
|
||||||
|
|
||||||
private static final String[] INTERNAL_WHITE_LIST_URL = {
|
private static final String[] INTERNAL_WHITE_LIST_URL = {
|
||||||
"/v2/api-docs",
|
"/v2/api-docs",
|
||||||
@ -61,11 +63,17 @@ public class SecurityConfiguration {
|
|||||||
private final UserDetailsService userDetailsService;
|
private final UserDetailsService userDetailsService;
|
||||||
|
|
||||||
private final LogoutHandler logoutHandler;
|
private final LogoutHandler logoutHandler;
|
||||||
|
private final CustomOAuth2UserService customOAuth2UserService;
|
||||||
|
private final OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SecurityConfiguration(UserDetailsService userDetailsService, LogoutHandler logoutHandler) {
|
public SecurityConfiguration(UserDetailsService userDetailsService, LogoutHandler logoutHandler,
|
||||||
|
CustomOAuth2UserService customOAuth2UserService,
|
||||||
|
OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler) {
|
||||||
this.userDetailsService = userDetailsService;
|
this.userDetailsService = userDetailsService;
|
||||||
this.logoutHandler = logoutHandler;
|
this.logoutHandler = logoutHandler;
|
||||||
|
this.customOAuth2UserService = customOAuth2UserService;
|
||||||
|
this.oAuth2AuthenticationSuccessHandler = oAuth2AuthenticationSuccessHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -111,12 +119,14 @@ public class SecurityConfiguration {
|
|||||||
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
|
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
|
||||||
.authenticationProvider(authenticationProvider())
|
.authenticationProvider(authenticationProvider())
|
||||||
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
||||||
|
.oauth2Login(oauth -> oauth
|
||||||
|
.userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService))
|
||||||
|
.successHandler(oAuth2AuthenticationSuccessHandler)
|
||||||
|
)
|
||||||
.logout(logout -> logout
|
.logout(logout -> logout
|
||||||
.logoutUrl("/api/v1/auth/logout")
|
.logoutUrl("/api/v1/auth/logout")
|
||||||
.addLogoutHandler(logoutHandler)
|
.addLogoutHandler(logoutHandler)
|
||||||
.logoutSuccessHandler((request,
|
.logoutSuccessHandler((req, res, auth) -> SecurityContextHolder.clearContext()));
|
||||||
response,
|
|
||||||
authentication) -> SecurityContextHolder.clearContext()));
|
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,28 @@ spring:
|
|||||||
timeout: 3000
|
timeout: 3000
|
||||||
writetimeout: 5000
|
writetimeout: 5000
|
||||||
|
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
client:
|
||||||
|
registration:
|
||||||
|
google:
|
||||||
|
client-id: ${GOOGLE_CLIENT_ID:}
|
||||||
|
client-secret: ${GOOGLE_CLIENT_SECRET:}
|
||||||
|
scope: openid,profile,email
|
||||||
|
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
|
||||||
|
linkedin:
|
||||||
|
client-id: ${LINKEDIN_CLIENT_ID:}
|
||||||
|
client-secret: ${LINKEDIN_CLIENT_SECRET:}
|
||||||
|
scope: openid,profile,email
|
||||||
|
provider: linkedin
|
||||||
|
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
|
||||||
|
provider:
|
||||||
|
linkedin:
|
||||||
|
authorization-uri: https://www.linkedin.com/oauth/v2/authorization
|
||||||
|
token-uri: https://www.linkedin.com/oauth/v2/accessToken
|
||||||
|
user-info-uri: https://api.linkedin.com/v2/userinfo
|
||||||
|
user-name-attribute: sub
|
||||||
|
|
||||||
application:
|
application:
|
||||||
email:
|
email:
|
||||||
from: randommailjf@gmail.com
|
from: randommailjf@gmail.com
|
||||||
|
|||||||
@ -51,6 +51,28 @@ spring:
|
|||||||
timeout: 3000
|
timeout: 3000
|
||||||
writetimeout: 5000
|
writetimeout: 5000
|
||||||
|
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
client:
|
||||||
|
registration:
|
||||||
|
google:
|
||||||
|
client-id: ${GOOGLE_CLIENT_ID:}
|
||||||
|
client-secret: ${GOOGLE_CLIENT_SECRET:}
|
||||||
|
scope: openid,profile,email
|
||||||
|
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
|
||||||
|
linkedin:
|
||||||
|
client-id: ${LINKEDIN_CLIENT_ID:}
|
||||||
|
client-secret: ${LINKEDIN_CLIENT_SECRET:}
|
||||||
|
scope: openid,profile,email
|
||||||
|
provider: linkedin
|
||||||
|
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
|
||||||
|
provider:
|
||||||
|
linkedin:
|
||||||
|
authorization-uri: https://www.linkedin.com/oauth/v2/authorization
|
||||||
|
token-uri: https://www.linkedin.com/oauth/v2/accessToken
|
||||||
|
user-info-uri: https://api.linkedin.com/v2/userinfo
|
||||||
|
user-name-attribute: sub
|
||||||
|
|
||||||
application:
|
application:
|
||||||
email:
|
email:
|
||||||
from: contact@leblr.fr
|
from: contact@leblr.fr
|
||||||
|
|||||||
@ -1,10 +1,22 @@
|
|||||||
package com.dh7789dev.xpeditis;
|
package com.dh7789dev.xpeditis;
|
||||||
|
|
||||||
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.UserAccount;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface UserService {
|
public interface UserService {
|
||||||
|
|
||||||
void changePassword(ChangePasswordRequest request, Principal connectedUser);
|
void changePassword(ChangePasswordRequest request, Principal connectedUser);
|
||||||
|
|
||||||
|
UserAccount create(UserAccount user);
|
||||||
|
|
||||||
|
UserAccount update(Long id, UserAccount user);
|
||||||
|
|
||||||
|
UserAccount getById(Long id);
|
||||||
|
|
||||||
|
List<UserAccount> list();
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package com.dh7789dev.xpeditis;
|
package com.dh7789dev.xpeditis;
|
||||||
|
|
||||||
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.UserAccount;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserServiceImpl implements UserService {
|
public class UserServiceImpl implements UserService {
|
||||||
@ -18,4 +20,29 @@ public class UserServiceImpl implements UserService {
|
|||||||
public void changePassword(ChangePasswordRequest request, Principal connectedUser) {
|
public void changePassword(ChangePasswordRequest request, Principal connectedUser) {
|
||||||
userRepository.changePassword(request, connectedUser);
|
userRepository.changePassword(request, connectedUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount create(UserAccount user) {
|
||||||
|
return userRepository.create(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount update(Long id, UserAccount user) {
|
||||||
|
return userRepository.update(id, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount getById(Long id) {
|
||||||
|
return userRepository.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserAccount> list() {
|
||||||
|
return userRepository.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Long id) {
|
||||||
|
userRepository.delete(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,22 @@
|
|||||||
package com.dh7789dev.xpeditis;
|
package com.dh7789dev.xpeditis;
|
||||||
|
|
||||||
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.UserAccount;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface UserRepository {
|
public interface UserRepository {
|
||||||
|
|
||||||
void changePassword(ChangePasswordRequest request, Principal connectedUser);
|
void changePassword(ChangePasswordRequest request, Principal connectedUser);
|
||||||
|
|
||||||
|
UserAccount create(UserAccount user);
|
||||||
|
|
||||||
|
UserAccount update(Long id, UserAccount user);
|
||||||
|
|
||||||
|
UserAccount getById(Long id);
|
||||||
|
|
||||||
|
List<UserAccount> list();
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,10 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
|||||||
@ -6,12 +6,16 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
public interface UserDao extends JpaRepository<UserEntity, Long> {
|
public interface UserDao extends JpaRepository<UserEntity, Long> {
|
||||||
|
|
||||||
@Query("SELECT u FROM UserEntity u WHERE u.username = :username")
|
@Query("SELECT u FROM UserEntity u WHERE u.username = :username")
|
||||||
Optional<UserEntity> findByUsername(String username);
|
Optional<UserEntity> findByUsername(String username);
|
||||||
boolean existsByUsername(String username);
|
boolean existsByUsername(String username);
|
||||||
|
Optional<UserEntity> findByEmail(String email);
|
||||||
|
boolean existsByEmail(String email);
|
||||||
|
|
||||||
|
@Query("SELECT u FROM UserEntity u WHERE u.username = :identifier OR u.email = :identifier")
|
||||||
|
Optional<UserEntity> findByUsernameOrEmail(String identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public class AuthenticationJwtRepository implements AuthenticationRepository {
|
|||||||
@Override
|
@Override
|
||||||
public AuthenticationResponse authenticate(AuthenticationRequest request) {
|
public AuthenticationResponse authenticate(AuthenticationRequest request) {
|
||||||
|
|
||||||
log.info("username: {}, password: {}", request.getUsername(), request.getPassword());
|
log.info("identifier: {}", request.getUsername());
|
||||||
UsernamePasswordAuthenticationToken authToken = UsernamePasswordAuthenticationToken
|
UsernamePasswordAuthenticationToken authToken = UsernamePasswordAuthenticationToken
|
||||||
.unauthenticated(request.getUsername(), request.getPassword());
|
.unauthenticated(request.getUsername(), request.getPassword());
|
||||||
Authentication authentication = authenticationManager.authenticate(authToken);
|
Authentication authentication = authenticationManager.authenticate(authToken);
|
||||||
@ -42,7 +42,7 @@ public class AuthenticationJwtRepository implements AuthenticationRepository {
|
|||||||
throw new UsernameNotFoundException("Failed to authenticate");
|
throw new UsernameNotFoundException("Failed to authenticate");
|
||||||
}
|
}
|
||||||
|
|
||||||
var userEntity = userDao.findByUsername(request.getUsername()).orElseThrow();
|
var userEntity = userDao.findByUsernameOrEmail(request.getUsername()).orElseThrow();
|
||||||
|
|
||||||
var jwtToken = jwtUtil.generateToken(userEntity);
|
var jwtToken = jwtUtil.generateToken(userEntity);
|
||||||
var refreshToken = jwtUtil.generateRefreshToken(userEntity);
|
var refreshToken = jwtUtil.generateRefreshToken(userEntity);
|
||||||
|
|||||||
@ -4,12 +4,18 @@ import com.dh7789dev.xpeditis.UserRepository;
|
|||||||
import com.dh7789dev.xpeditis.dao.UserDao;
|
import com.dh7789dev.xpeditis.dao.UserDao;
|
||||||
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
||||||
import com.dh7789dev.xpeditis.entity.UserEntity;
|
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.UserAccount;
|
||||||
|
import com.dh7789dev.xpeditis.entity.Role;
|
||||||
|
import com.dh7789dev.xpeditis.dao.CompanyDao;
|
||||||
|
import com.dh7789dev.xpeditis.mapper.UserMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class UserJpaRepository implements UserRepository {
|
public class UserJpaRepository implements UserRepository {
|
||||||
@ -17,11 +23,15 @@ public class UserJpaRepository implements UserRepository {
|
|||||||
private final UserDao userDao;
|
private final UserDao userDao;
|
||||||
|
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final CompanyDao companyDao;
|
||||||
|
private final UserMapper userMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public UserJpaRepository(UserDao userDao, PasswordEncoder passwordEncoder) {
|
public UserJpaRepository(UserDao userDao, PasswordEncoder passwordEncoder, CompanyDao companyDao, UserMapper userMapper) {
|
||||||
this.userDao = userDao;
|
this.userDao = userDao;
|
||||||
this.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
this.companyDao = companyDao;
|
||||||
|
this.userMapper = userMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -42,4 +52,55 @@ public class UserJpaRepository implements UserRepository {
|
|||||||
userEntity.setPassword(passwordEncoder.encode(request.getNewPassword()));
|
userEntity.setPassword(passwordEncoder.encode(request.getNewPassword()));
|
||||||
userDao.save(userEntity);
|
userDao.save(userEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount create(UserAccount user) {
|
||||||
|
UserEntity entity = userMapper.userAccountToUserEntity(user);
|
||||||
|
if (user.getPassword() != null) {
|
||||||
|
entity.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||||
|
}
|
||||||
|
if (user.getRole() != null) {
|
||||||
|
entity.setRole(Role.valueOf(user.getRole()));
|
||||||
|
}
|
||||||
|
if (user.getCompany() != null && user.getCompany().getId() != null) {
|
||||||
|
companyDao.findById(user.getCompany().getId()).ifPresent(entity::setCompany);
|
||||||
|
}
|
||||||
|
entity.setEnabled(true);
|
||||||
|
UserEntity saved = userDao.save(entity);
|
||||||
|
return userMapper.userEntityToUserAccount(saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount update(Long id, UserAccount user) {
|
||||||
|
UserEntity entity = userDao.findById(id).orElseThrow();
|
||||||
|
if (user.getFirstName() != null) entity.setFirstName(user.getFirstName());
|
||||||
|
if (user.getLastName() != null) entity.setLastName(user.getLastName());
|
||||||
|
if (user.getEmail() != null) entity.setEmail(user.getEmail());
|
||||||
|
if (user.getUsername() != null) entity.setUsername(user.getUsername());
|
||||||
|
if (user.getRole() != null) entity.setRole(Role.valueOf(user.getRole()));
|
||||||
|
if (user.getCompany() != null && user.getCompany().getId() != null) {
|
||||||
|
companyDao.findById(user.getCompany().getId()).ifPresent(entity::setCompany);
|
||||||
|
}
|
||||||
|
UserEntity saved = userDao.save(entity);
|
||||||
|
return userMapper.userEntityToUserAccount(saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount getById(Long id) {
|
||||||
|
return userDao.findById(id)
|
||||||
|
.map(userMapper::userEntityToUserAccount)
|
||||||
|
.orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserAccount> list() {
|
||||||
|
return userDao.findAll().stream()
|
||||||
|
.map(userMapper::userEntityToUserAccount)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Long id) {
|
||||||
|
userDao.deleteById(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user