diff --git a/.gitignore b/.gitignore index ad4f918..1ad7e35 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ target/ demo*/ .idea/dictionaries/ etunicorn.db +.idea/dataSources diff --git a/.idea/dataSources/0d8f27ad-8161-4ee1-8557-56db7fbf44cc/storage.xml b/.idea/dataSources/0d8f27ad-8161-4ee1-8557-56db7fbf44cc/storage.xml deleted file mode 100644 index 6c5306d..0000000 --- a/.idea/dataSources/0d8f27ad-8161-4ee1-8557-56db7fbf44cc/storage.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/dataSources/a06fd1f6-5928-4430-a317-e5ebc0e00a82/storage.xml b/.idea/dataSources/a06fd1f6-5928-4430-a317-e5ebc0e00a82/storage.xml deleted file mode 100644 index 6c5306d..0000000 --- a/.idea/dataSources/a06fd1f6-5928-4430-a317-e5ebc0e00a82/storage.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/dataSources/a88dec51-cb33-4875-a137-6d17703d6d6c/storage.xml b/.idea/dataSources/a88dec51-cb33-4875-a137-6d17703d6d6c/storage.xml deleted file mode 100644 index 6c5306d..0000000 --- a/.idea/dataSources/a88dec51-cb33-4875-a137-6d17703d6d6c/storage.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/dataSources/ebfeef5a-f196-4340-9424-14e4e8aaadbb.xml b/.idea/dataSources/ebfeef5a-f196-4340-9424-14e4e8aaadbb.xml deleted file mode 100644 index 1aad0f6..0000000 --- a/.idea/dataSources/ebfeef5a-f196-4340-9424-14e4e8aaadbb.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - 1 - 1 - - - - INTEGER(0,-1)|4 - - - 1 - VARCHAR(0,-1)|12 - - - 2 - VARCHAR(0,-1)|12 - - - 3 - TIMESTAMP(0,-1)|12 - - - id - 1 - - - \ No newline at end of file diff --git a/.idea/dataSources/ebfeef5a-f196-4340-9424-14e4e8aaadbb/storage.xml b/.idea/dataSources/ebfeef5a-f196-4340-9424-14e4e8aaadbb/storage.xml deleted file mode 100644 index 3d9a470..0000000 --- a/.idea/dataSources/ebfeef5a-f196-4340-9424-14e4e8aaadbb/storage.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/src/main/java/etunicorn/Application.java b/src/main/java/etunicorn/Application.java index 1356403..bfd0d7f 100644 --- a/src/main/java/etunicorn/Application.java +++ b/src/main/java/etunicorn/Application.java @@ -8,6 +8,9 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; /** * etunicorn-server @@ -23,17 +26,33 @@ public class Application { } @Bean - public CommandLineRunner demo(PermissionRepository permissionRepository) { + public CommandLineRunner demo(PermissionRepository permissionRepository, + RoleRepository roleRepository, + PersonneRepository personneRepository, + SessionRepository sessionRepository) { return (args) -> { - permissionRepository.save(new Permission("ROLE_ADMIN")); - permissionRepository.save(new Permission("CONSO_ADMIN")); - permissionRepository.save(new Permission("EVNMT_ADMIN")); + permissionRepository.save(new Permission("PERSONNE_ADD")); + permissionRepository.save(new Permission("PERSONNE_EDIT")); + permissionRepository.save(new Permission("PERSONNE_GET")); + permissionRepository.save(new Permission("PERSONNE_LIST")); + permissionRepository.save(new Permission("PERSONNE_REMOVE")); + permissionRepository.save(new Permission("ROLE_ADD")); + permissionRepository.save(new Permission("ROLE_DELETE")); + permissionRepository.save(new Permission("ROLE_PERMISSION_ADD")); + permissionRepository.save(new Permission("ROLE_PERMISSION_LIST")); + permissionRepository.save(new Permission("ROLE_PERMISSION_REMOVE")); // ... + + roleRepository.save(new Role("admin", (List) permissionRepository.findAll())); + roleRepository.save(new Role("etudiant", new ArrayList<>())); + personneRepository.save(new Personne("carte", new Date(), "gbontoux", roleRepository.findByNom("admin"))); + sessionRepository.save(new Session(personneRepository.findByLogin("gbontoux"), "A", new Date(new Date().getTime() + 1000 * 60 * 10))); + }; } @Bean - public DataSource dataSource(){ + public DataSource dataSource() { DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); dataSourceBuilder.driverClassName("org.sqlite.JDBC"); dataSourceBuilder.url("jdbc:sqlite:etunicorn.db"); diff --git a/src/main/java/etunicorn/BaseController.java b/src/main/java/etunicorn/BaseController.java new file mode 100644 index 0000000..b222de9 --- /dev/null +++ b/src/main/java/etunicorn/BaseController.java @@ -0,0 +1,36 @@ +package etunicorn; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +/** + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés + */ +@RestController +public class BaseController { + + // Permettent la vérification de permissions dans les méthodes de controlleur + @Autowired + private HttpServletRequest request; + @Autowired + private SessionService sessionService; + @Autowired + private PermissionRepository permissionRepository; + + protected boolean hasPermission(Permission permission) { + Session session = sessionService.getSession(request); + if (session == null || permission == null) { + return false; + } + return session.hasPermission(permission); + } + + protected boolean hasPermission(String nomPermission) { + Permission permission = permissionRepository.findByNom(nomPermission); + return hasPermission(permission); + } +} diff --git a/src/main/java/etunicorn/LoginController.java b/src/main/java/etunicorn/LoginController.java index b64be71..4fd0009 100644 --- a/src/main/java/etunicorn/LoginController.java +++ b/src/main/java/etunicorn/LoginController.java @@ -7,8 +7,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.Date; - /** * etunicorn-server * Copyright © 2017 Le Club Info Polytech Lille @@ -17,22 +15,27 @@ import java.util.Date; @RestController public class LoginController implements etunicorn.generated.LoginController { @Autowired - private PermissionRepository permissionRepository; + private PersonneRepository personneRepository; + + @Autowired + private SessionService sessionService; @Override + @RestrictedTo(authentifie = false) public ResponseEntity updateLogin(@RequestParam String login, @RequestParam String password) { - // TODO C'est du debug ! - Role role = new Role(); - role.setNom("superman"); - for (Permission permission : permissionRepository.findAll()) { - role.addPermission(permission); + Personne personne = personneRepository.findByLogin(login); + if (personne == null) { + return new ResponseEntity(HttpStatus.UNAUTHORIZED); } - Personne personne = new Personne(); - personne.setLogin("gbontoux"); - personne.setCarte("39cdd9ed0b191d"); - personne.setNaissance(new Date("14-Feb-1997")); - personne.setRole(role); - return new ResponseEntity(personne, HttpStatus.OK); + + // TODO Vraie vérification du mot de passe + if (!password.equals("test")) { + return new ResponseEntity(HttpStatus.UNAUTHORIZED); + } + + Session session = sessionService.createSession(personne); + + return new ResponseEntity(session, HttpStatus.OK); } @Override diff --git a/src/main/java/etunicorn/Personne.java b/src/main/java/etunicorn/Personne.java index 57477d5..f65e802 100644 --- a/src/main/java/etunicorn/Personne.java +++ b/src/main/java/etunicorn/Personne.java @@ -31,6 +31,13 @@ public class Personne { public Personne() { } + public Personne(String carte, Date naissance, String login, Role role) { + this.carte = carte; + this.naissance = naissance; + this.login = login; + this.role = role; + } + public int getId() { return id; } @@ -70,4 +77,8 @@ public class Personne { public void setRole(Role role) { this.role = role; } + + public boolean hasPermission(Permission permission) { + return role.hasPermission(permission); + } } diff --git a/src/main/java/etunicorn/PersonneController.java b/src/main/java/etunicorn/PersonneController.java index 2741442..2958931 100644 --- a/src/main/java/etunicorn/PersonneController.java +++ b/src/main/java/etunicorn/PersonneController.java @@ -19,7 +19,7 @@ import java.util.List; */ @RestController -public class PersonneController implements etunicorn.generated.PersonneController { +public class PersonneController extends BaseController implements etunicorn.generated.PersonneController { @Autowired private PersonneRepository personneRepository; @@ -27,10 +27,12 @@ public class PersonneController implements etunicorn.generated.PersonneControlle private RoleRepository roleRepository; @Override + @RestrictedTo("PERSONNE_LIST") public ResponseEntity getPersonne() { return new ResponseEntity((List) this.personneRepository.findAll(), HttpStatus.OK); } + private ResponseEntity mergePersonne(Personne personne, String carte, Date naissance, String login, String role) { if (carte != null) { personne.setCarte(carte); @@ -41,11 +43,16 @@ public class PersonneController implements etunicorn.generated.PersonneControlle if (login != null) { personne.setLogin(login); } + // TODO Il faut que login ou carte soient mis if (role != null) { - Role roleObj = roleRepository.findByNom(role); - personne.setRole(roleObj); - if (roleObj == null) { - return new ResponseEntity("Rôle inconnu", HttpStatus.NOT_FOUND); + if (hasPermission("PERSONNE_ROLE")) { + Role roleObj = roleRepository.findByNom(role); + personne.setRole(roleObj); + if (roleObj == null) { + return new ResponseEntity("Rôle inconnu", HttpStatus.NOT_FOUND); + } + } else { + return new ResponseEntity(HttpStatus.FORBIDDEN); } } try { @@ -57,12 +64,14 @@ public class PersonneController implements etunicorn.generated.PersonneControlle } @Override + @RestrictedTo("PERSONNE_ADD") public ResponseEntity updatePersonne(@RequestParam(required = false) String carte, @RequestParam(required = false) Date naissance, @RequestParam(required = false) String login, @RequestParam(required = false) String role) { Personne personne = new Personne(); return mergePersonne(personne, carte, naissance, login, role); } @Override + @RestrictedTo("PERSONNE_GET") public ResponseEntity getPersonneById(@PathVariable BigDecimal idPersonne) { Personne personne = personneRepository.findById(idPersonne.intValueExact()); if (personne == null) { @@ -72,6 +81,7 @@ public class PersonneController implements etunicorn.generated.PersonneControlle } @Override + @RestrictedTo("PERSONNE_EDIT") public ResponseEntity updatePersonneById(@PathVariable BigDecimal idPersonne, @RequestParam(required = false) String carte, @RequestParam(required = false) Date naissance, @RequestParam(required = false) String login, @RequestParam(required = false) String role) { Personne personne = personneRepository.findById(idPersonne.intValueExact()); if (personne == null) { @@ -81,6 +91,7 @@ public class PersonneController implements etunicorn.generated.PersonneControlle } @Override + @RestrictedTo("PERSONNE_REMOVE") public ResponseEntity deletePersonneById(@PathVariable BigDecimal idPersonne) { Personne personne = personneRepository.findById(idPersonne.intValueExact()); if (personne == null) { diff --git a/src/main/java/etunicorn/RestrictedTo.java b/src/main/java/etunicorn/RestrictedTo.java new file mode 100644 index 0000000..d12d7de --- /dev/null +++ b/src/main/java/etunicorn/RestrictedTo.java @@ -0,0 +1,17 @@ +package etunicorn; + +import java.lang.annotation.*; + +/** + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés + */ +@Target(value = {ElementType.METHOD, ElementType.PARAMETER}) +@Retention(value = RetentionPolicy.RUNTIME) +@Documented +public @interface RestrictedTo { + String value() default ""; + + boolean authentifie() default true; +} diff --git a/src/main/java/etunicorn/Role.java b/src/main/java/etunicorn/Role.java index 306a5b4..202fbab 100644 --- a/src/main/java/etunicorn/Role.java +++ b/src/main/java/etunicorn/Role.java @@ -25,6 +25,11 @@ public class Role { public Role() { } + public Role(String nom, List permissions) { + this.nom = nom; + this.permissions = permissions; + } + public String getNom() { return nom; } @@ -41,6 +46,10 @@ public class Role { this.permissions = permissions; } + public boolean hasPermission(Permission permission) { + return permissions.contains(permission); + } + public void addPermission(Permission permission) { this.permissions.add(permission); } diff --git a/src/main/java/etunicorn/RoleController.java b/src/main/java/etunicorn/RoleController.java index 90af66d..ad167bd 100644 --- a/src/main/java/etunicorn/RoleController.java +++ b/src/main/java/etunicorn/RoleController.java @@ -17,7 +17,7 @@ import java.util.List; * Tous droits réservés */ @RestController -public class RoleController implements etunicorn.generated.RoleController { +public class RoleController extends BaseController implements etunicorn.generated.RoleController { @Autowired private RoleRepository roleRepository; @@ -30,6 +30,7 @@ public class RoleController implements etunicorn.generated.RoleController { } @Override + @RestrictedTo("ROLE_ADD") public ResponseEntity updateRole(@RequestParam String nom) { Role oldRole = roleRepository.findByNom(nom); if (oldRole != null) { @@ -46,6 +47,7 @@ public class RoleController implements etunicorn.generated.RoleController { } @Override + @RestrictedTo("ROLE_DELETE") public ResponseEntity deleteRoleById(@PathVariable String nomRole) { Role role = roleRepository.findByNom(nomRole); if (role == null) { @@ -56,6 +58,7 @@ public class RoleController implements etunicorn.generated.RoleController { } @Override + @RestrictedTo("ROLE_PERMISSION_ADD") public ResponseEntity updateRoleById(@PathVariable String nomRole, @RequestParam String nom) { Role role = roleRepository.findByNom(nomRole); if (role == null) { @@ -75,6 +78,7 @@ public class RoleController implements etunicorn.generated.RoleController { } @Override + @RestrictedTo("ROLE_PERMISSION_REMOVE") public ResponseEntity deleteRoleByNomPermission(@PathVariable String nomPermission, @PathVariable String nomRole) { Role role = roleRepository.findByNom(nomRole); if (role == null) { @@ -90,6 +94,7 @@ public class RoleController implements etunicorn.generated.RoleController { } @Override + @RestrictedTo("ROLE_PERMISSION_LIST") public ResponseEntity getPermission() { return new ResponseEntity((List) permissionRepository.findAll(), HttpStatus.OK); } diff --git a/src/main/java/etunicorn/SecurityInterceptor.java b/src/main/java/etunicorn/SecurityInterceptor.java new file mode 100644 index 0000000..8469994 --- /dev/null +++ b/src/main/java/etunicorn/SecurityInterceptor.java @@ -0,0 +1,70 @@ +package etunicorn; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés + */ +public class SecurityInterceptor extends HandlerInterceptorAdapter { + @Autowired + SessionService sessionService; + @Autowired + PermissionRepository permissionRepository; + + public SecurityInterceptor() { + super(); + } + + @Override + @Transactional + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + Session session = sessionService.getSession(request); + + HandlerMethod method = (HandlerMethod) handler; + RestrictedTo annotation = method.getMethodAnnotation(RestrictedTo.class); + + Permission requiredPermission = permissionRepository.findByNom(annotation.value()); + if (requiredPermission == null) { + response.setStatus(HttpStatus.NOT_IMPLEMENTED.value()); + return false; + } + + if (annotation.authentifie()) { + if (session == null) { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return false; + } else { + if (!session.hasPermission(requiredPermission)) { + response.setStatus(HttpStatus.FORBIDDEN.value()); + return false; + } + } + } + return super.preHandle(request, response, handler); + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + super.postHandle(request, response, handler, modelAndView); + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + super.afterCompletion(request, response, handler, ex); + } + + @Override + public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + super.afterConcurrentHandlingStarted(request, response, handler); + } +} diff --git a/src/main/java/etunicorn/Session.java b/src/main/java/etunicorn/Session.java index e44d66a..08a5b8f 100644 --- a/src/main/java/etunicorn/Session.java +++ b/src/main/java/etunicorn/Session.java @@ -8,7 +8,9 @@ import java.security.SecureRandom; import java.util.Date; /** - * Created by geoffrey on 04/02/17. + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés */ @Entity public class Session { @@ -16,11 +18,11 @@ public class Session { // Durée par défaut d'une session en secondes private static final int SESSION_DURATION = 10 * 60; private static SecureRandom random = new SecureRandom(); + // TODO Vérifier si c'est bien initialisé qu'une seule fois par éxecution car c'est lourd à initialiser @ManyToOne private Personne personne; @Id private String token; - // TODO Vérifier si c'est bien initialisé qu'une seule fois par éxecution car c'est lourd à initialiser private Date validity; @@ -34,6 +36,12 @@ public class Session { this.validity = new Date(new Date().getTime() + SESSION_DURATION * 1000); } + public Session(Personne personne, String token, Date validity) { + this.personne = personne; + this.token = token; + this.validity = validity; + } + public Personne getPersonne() { return personne; } @@ -57,4 +65,8 @@ public class Session { public void setValidity(Date validity) { this.validity = validity; } + + public boolean hasPermission(Permission permission) { + return personne.hasPermission(permission); + } } diff --git a/src/main/java/etunicorn/SessionRepository.java b/src/main/java/etunicorn/SessionRepository.java index 324ef0f..ae6af90 100644 --- a/src/main/java/etunicorn/SessionRepository.java +++ b/src/main/java/etunicorn/SessionRepository.java @@ -3,7 +3,9 @@ package etunicorn; import org.springframework.data.repository.CrudRepository; /** - * Created by geoffrey on 04/02/17. + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés */ public interface SessionRepository extends CrudRepository { Session findByToken(String token); diff --git a/src/main/java/etunicorn/SessionService.java b/src/main/java/etunicorn/SessionService.java new file mode 100644 index 0000000..665b304 --- /dev/null +++ b/src/main/java/etunicorn/SessionService.java @@ -0,0 +1,58 @@ +package etunicorn; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.Date; + +/** + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés + */ +@Service("sessionService") +public class SessionService { + @Autowired + private SessionRepository sessionRepository; + @Autowired + private PersonneRepository personneRepository; + + public SessionService() { + } + + public Session getSession(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + return getSession(token); + } + + public Session getSession(String token) { + if (token == null) { + return null; + } else { + Session session = sessionRepository.findByToken(token); + if (session == null) { + return null; + } else { + if (session.getValidity().compareTo(new Date()) < 0) { + return null; + } else { + // Vérifie si la personne est toujours dans la base de données + Personne personne = personneRepository.findById(session.getPersonne().getId()); + if (personne == null) { + return null; + } else { + return session; + } + } + } + } + } + + public Session createSession(Personne personne) { + Session session = new Session(personne); + sessionRepository.save(session); + return session; + } + +} diff --git a/src/main/java/etunicorn/WebMvcConfig.java b/src/main/java/etunicorn/WebMvcConfig.java index 6c1bd35..50c5ea9 100644 --- a/src/main/java/etunicorn/WebMvcConfig.java +++ b/src/main/java/etunicorn/WebMvcConfig.java @@ -1,5 +1,6 @@ package etunicorn; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @@ -13,9 +14,16 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { + // http://stackoverflow.com/a/18218439 + @Bean + public SecurityInterceptor securityInterceptor() { + return new SecurityInterceptor(); + } + @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new GitHeaderInterceptor()); + registry.addInterceptor(securityInterceptor()); } } diff --git a/src/main/java/etunicorn/databaseConfiguration/SQLiteDialect.java b/src/main/java/etunicorn/databaseConfiguration/SQLiteDialect.java index 15dcda1..f10299b 100644 --- a/src/main/java/etunicorn/databaseConfiguration/SQLiteDialect.java +++ b/src/main/java/etunicorn/databaseConfiguration/SQLiteDialect.java @@ -1,7 +1,9 @@ package etunicorn.databaseConfiguration; /** - * Created by badet on 29/01/2017. + * etunicorn-server + * Copyright © 2017 Le Club Info Polytech Lille + * Tous droits réservés */ import org.hibernate.dialect.Dialect; -- libgit2 0.21.2