Skip to content
Snippets Groups Projects
Commit c6c97bac authored by KASMAMYTOV ELDAR p1712650's avatar KASMAMYTOV ELDAR p1712650 :computer:
Browse files

Merge branch 'TP2' into TP3

parents dcc4623c d96adccb
No related branches found
No related tags found
No related merge requests found
Pipeline #86056 failed
Showing
with 166 additions and 123 deletions
......@@ -3,6 +3,7 @@ package com.mif13.authServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
// extends SpringBootServletInitializer for .war generation
@SpringBootApplication
public class AuthServerApplication extends SpringBootServletInitializer {
......
......@@ -3,30 +3,25 @@ package com.mif13.authServer.controllers;
import com.mif13.authServer.dao.UsersDao;
import com.mif13.authServer.model.User;
import com.mif13.authServer.utils.JwtHelper;
import java.io.Console;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.naming.AuthenticationException;
import javax.ws.rs.POST;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.util.MultiValueMapAdapter;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserOperations {
......@@ -38,7 +33,6 @@ public class UserOperations {
this.usersRepo = usersRepo;
}
/**
* Procédure de login utilisée par un utilisateur
*
......@@ -53,10 +47,10 @@ public class UserOperations {
@ApiResponse(
responseCode = "204 No Content",
description = "User succesfully logged in",
content = {
@Content ()
}
),
content = {
@Content()
}
),
@ApiResponse(
responseCode = "401 Unauthorized",
description = "Login failed",
......@@ -70,9 +64,6 @@ public class UserOperations {
@RequestParam("password") String password, @RequestHeader("Origin") String origin) {
ResponseEntity<Void> response;
response = new ResponseEntity<>(HttpStatus.NO_CONTENT);
/*response.getHeaders().add("Access-Control-Expose-Headers", "Authorization");
response.getHeaders().add("Access-Control-Allow-Origin", origin);*/
String jwt;
Map<String, List<String>> headers = new HashMap<>();
......@@ -120,16 +111,15 @@ public class UserOperations {
return response;
}
@Operation(summary = "Réalise la déconnexion.")
@ApiResponses(value = {
@ApiResponse(
responseCode = "204 No Content",
description = "User succesfully logged out",
content = {
@Content ()
}
),
content = {
@Content()
}
),
@ApiResponse(
responseCode = "401 Unauthorized",
description = "",
......@@ -160,7 +150,7 @@ public class UserOperations {
} catch (Exception e) {
e.printStackTrace();
response = new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
return response;
}
......@@ -177,16 +167,16 @@ public class UserOperations {
@ApiResponse(
responseCode = "204 No Content",
description = "",
content = {
@Content ()
}
)
content = {
@Content()
}
)
})
@GetMapping("/authenticate")
public ResponseEntity<Void> authenticate(@RequestParam("jwt") String jwt,
@RequestParam("origin") String origin) {
ResponseEntity<Void> response = new ResponseEntity<>(HttpStatus.NO_CONTENT);
return response;
}
}
\ No newline at end of file
package com.mif13.authServer.controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mif13.authServer.dao.UsersDao;
import com.mif13.authServer.exception.InvalidPasswordException;
import com.mif13.authServer.exception.InvalidUsernameException;
import com.mif13.authServer.exception.UserCreationException;
import com.mif13.authServer.model.User;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import java.util.Optional;
import java.util.regex.PatternSyntaxException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
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 org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@RestController
@RequestMapping(value = "users")
public class UserRestController {
......@@ -64,24 +69,20 @@ public class UserRestController {
}
)}
)
@GetMapping(value = "/{id}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
@GetMapping(value = "/{id}", produces = {MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
//@CrossOrigin(origins = {"http://localhost", "http://192.168.75.68", "https://192.168.75.68"})
public ResponseEntity<User> getUserAsJsonOrXml(@PathVariable String id) {
ResponseEntity<User> response;
Optional<User> optionalUser = usersRepo.get(id);
if (optionalUser.isPresent()) {
User user = optionalUser.get();
response = new ResponseEntity<>(user, HttpStatus.OK);
return response;
return new ResponseEntity<>(user, HttpStatus.OK);
} else {
response = new ResponseEntity<>(HttpStatus.NOT_FOUND);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");
}
return response;
}
@GetMapping(value = "/{id}", produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView getUserAsHtml(@PathVariable String id, Model model) {
// "user" nom du template HTML (sans extension)
......@@ -104,23 +105,45 @@ public class UserRestController {
return modelAndView;
}
private ResponseEntity<Void> createUser(User user) {
ResponseEntity<Void> response;
private ResponseEntity<Void> createUserResponse(String login, String password) {
try {
Optional<User> optionalUser = usersRepo.get(user.getLogin());
if (optionalUser.isEmpty()) {
usersRepo.save(user);
response = new ResponseEntity<>(HttpStatus.CREATED);
} else {
response = new ResponseEntity<>(HttpStatus.FORBIDDEN);
User user = new User(login, password);
try {
HttpStatus statusCode;
Optional<User> optionalUser = usersRepo.get(user.getLogin());
if (optionalUser.isEmpty()) {
usersRepo.save(user);
statusCode = HttpStatus.CREATED;
} else {
statusCode = HttpStatus.FORBIDDEN;
}
return new ResponseEntity<>(statusCode);
} catch (PatternSyntaxException e) {
// Si les patterns RegEx de validation sont pas valides
e.printStackTrace();
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
} catch (PatternSyntaxException e) {
} catch (UserCreationException e) {
e.printStackTrace();
response = new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
String errMsg;
if (e instanceof InvalidUsernameException) {
errMsg = "Login does not match the requirements";
} else if (e instanceof InvalidPasswordException) {
errMsg = "Password does not match the requirements";
} else {
errMsg = "Failed to create a user";
}
// Par defaut, pour des raisons de securite,
// le message d'erreur n'est pas affiche a l'utilisateur
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, errMsg, e);
}
return response;
}
@Operation(summary = "Create a new user")
......@@ -159,33 +182,30 @@ public class UserRestController {
@PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<Void> createUserFromUrlEncoded(@RequestParam("login") String login,
@RequestParam("password") String password) {
ResponseEntity<Void> response;
try {
User user = new User(login, password);
response = createUser(user);
} catch (UserCreationException e) {
e.printStackTrace();
response = new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return response;
return createUserResponse(login, password);
}
/**
* Cree un User a partir d'un JSON.
*
* /!\ Attention /!\
* Renvoie 400 BAD_REQUEST si le login ou le password sont invalides
* (et produit une HttpMessageNotReadableException)
*
* @param user JSON converti en User (converter de Spring)
* @param json JSON contenant un login et un password
* @return contenu vide
**/
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> createUserFromJson(@RequestBody User user) {
return createUser(user);
}
public ResponseEntity<Void> createUserFromJson(@RequestBody String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonTree = objectMapper.readTree(json);
String login = jsonTree.get("login").asText();
String password = jsonTree.get("password").asText();
return createUserResponse(login, password);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to process JSON", e);
}
}
@Operation(summary = "Modify password of a user by its id")
@ApiResponses(value = {
......@@ -211,10 +231,28 @@ public class UserRestController {
}
)
})
@PutMapping("/{id}")
public ResponseEntity<Void> modifyUserPassword(@PathVariable String id,
@RequestParam("new_password") String newPassword) {
ResponseEntity<Void> response;
@PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<Void> modifyUserPasswordFromUrlEncoded(@PathVariable String id,
@RequestParam("newPassword") String newPassword) {
return modifyUserPassword(id, newPassword);
}
@PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> modifyUserPasswordFromJson(@PathVariable String id,
@RequestBody String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonTree = objectMapper.readTree(json);
String newPassword = jsonTree.get("newPassword").asText();
return modifyUserPassword(id, newPassword);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to process JSON", e);
}
}
private ResponseEntity<Void> modifyUserPassword(String id, String newPassword) {
Optional<User> optionalUser = usersRepo.get(id);
if (optionalUser.isPresent()) {
......@@ -223,20 +261,19 @@ public class UserRestController {
try {
if (User.verifyPassword(newPassword)) {
user.setPassword(newPassword);
response = new ResponseEntity<>(HttpStatus.NO_CONTENT);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
throw new InvalidPasswordException("Password is too weak");
throw new InvalidPasswordException("Password does not match the requirements");
}
} catch (InvalidPasswordException e) {
e.printStackTrace();
response = new ResponseEntity<>(HttpStatus.BAD_REQUEST);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
}
} else {
response = new ResponseEntity<>(HttpStatus.NOT_FOUND);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");
}
return response;
}
@Operation(summary = "Delete a user on the database, by its id")
......@@ -265,19 +302,16 @@ public class UserRestController {
})
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable String id) {
ResponseEntity<Void> response;
Optional<User> optionalUser = usersRepo.get(id);
if (optionalUser.isPresent()) {
User user = optionalUser.get();
usersRepo.delete(user);
response = new ResponseEntity<>(HttpStatus.NO_CONTENT);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
response = new ResponseEntity<>(HttpStatus.NOT_FOUND);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");
}
return response;
}
}
......@@ -4,8 +4,10 @@ import java.util.Optional;
import java.util.Set;
public interface Dao<T> {
/**
* Récupère un utilisateur enregistré
*
* @param id Login de l'utilisateur
* @return Un java.util.Optional qui contient (ou pas) l'utilisateur
*/
......@@ -13,25 +15,29 @@ public interface Dao<T> {
/**
* Récupère tous les utilisateurs enregistrés
*
* @return Un Set de login
*/
Set<String> getAll();
/**
* Crée un utilisateur et le sauvegarde
*
* @param t L'utilisateur à créer
*/
void save(T t);
/**
* Modifie un utilisateur enregistré
* @param t L'utilisateur à modifier
*
* @param t L'utilisateur à modifier
* @param password Le nouveau password
*/
void update(T t, String password);
/**
* Supprime un utilisateur enregistré
*
* @param t L'utilisateur à supprimer
*/
void delete(T t);
......
package com.mif13.authServer.exception;
public class InvalidPasswordException extends UserCreationException {
public InvalidPasswordException() {}
public InvalidPasswordException() {
}
public InvalidPasswordException(String errorMessage) {
super(errorMessage);
}
......
package com.mif13.authServer.exception;
public class InvalidUsernameException extends UserCreationException {
public InvalidUsernameException() {}
public InvalidUsernameException() {
}
public InvalidUsernameException(String errorMessage) {
super(errorMessage);
}
......
package com.mif13.authServer.exception;
public class UserCreationException extends Exception {
public UserCreationException() {}
public UserCreationException() {
}
public UserCreationException(String errorMessage) {
super(errorMessage);
}
......
......@@ -7,6 +7,7 @@ import java.util.regex.PatternSyntaxException;
import javax.naming.AuthenticationException;
public class User {
private final String login;
private String password;
......@@ -26,6 +27,17 @@ public class User {
}
}
public static boolean verifyLogin(String login) throws PatternSyntaxException {
String regex = "^[a-zA-Z][a-zA-Z0-9._-]{3,20}$";
return login.matches(regex);
}
public static boolean verifyPassword(String password) throws PatternSyntaxException {
String regex =
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#&()–[{}]:;',?/*~$^+=<>]).{8,25}$";
return password.matches(regex);
}
public String getLogin() {
return login;
}
......@@ -59,15 +71,4 @@ public class User {
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#&()–[{}]:;',?/*~$^+=<>]).{8,25}$";
return password.matches(regex);
}
public static boolean verifyLogin(String login) throws PatternSyntaxException {
String regex = "^[a-zA-Z][a-zA-Z0-9._-]{3,20}$";
return login.matches(regex);
}
public static boolean verifyPassword(String password) throws PatternSyntaxException {
String regex =
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#&()–[{}]:;',?/*~$^+=<>]).{8,25}$";
return password.matches(regex);
}
}
\ No newline at end of file
......@@ -9,35 +9,39 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class CorsConfig {
@Bean
public WebMvcConfigurer configure(){
public WebMvcConfigurer configure() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry){
public void addCorsMappings(CorsRegistry registry) {
// CORS for /login POST - CORS pas reglé
registry.addMapping("/login")
.allowedMethods("POST")
.allowedHeaders("*", "Authorization")
.allowedOrigins("http://localhost", "http://192.168.75.68", "https://192.168.75.68","https://localhost");
.allowedOrigins("http://localhost", "http://192.168.75.68",
"https://192.168.75.68", "https://localhost");
// CORS for /lougout POST - CORS pas reglé
registry.addMapping("/logout")
.allowedMethods("POST")
.allowedHeaders("*", "Authorization")
.allowedOrigins("http://localhost", "http://192.168.75.68", "https://192.168.75.68","https://localhost");
.allowedOrigins("http://localhost", "http://192.168.75.68",
"https://192.168.75.68", "https://localhost");
// CORS for /authenticate GET - Fonctionne
registry.addMapping("/authenticate")
.allowedMethods("GET")
.allowedHeaders("*")
.allowedOrigins("http://localhost", "http://192.168.75.68", "https://192.168.75.68","https://localhost");
.allowedOrigins("http://localhost", "http://192.168.75.68",
"https://192.168.75.68", "https://localhost");
// CORS for /users/{id} GET - Fonctionne
registry.addMapping("/{id}")
.allowedMethods("GET")
.allowedHeaders("*")
.allowedOrigins("http://localhost", "http://192.168.75.68", "https://192.168.75.68","https://localhost");
.allowedOrigins("http://localhost", "http://192.168.75.68",
"https://192.168.75.68", "https://localhost");
}
};
}
......
......@@ -6,9 +6,8 @@ import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import javax.validation.constraints.NotNull;
import java.util.Date;
import javax.validation.constraints.NotNull;
/**
* Classe qui centralise les opérations de validation et de génération d'un token "métier",
......@@ -67,5 +66,4 @@ public class JwtHelper {
.sign(algorithm);
}
}
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