diff --git a/TD4/pom.xml b/TD4/pom.xml
index 8b89a3cbfea0c29af07b14d2d0cd1d3caa8a7f5e..267a71e28f5f49050f7d7d36122699b1478f2c46 100644
--- a/TD4/pom.xml
+++ b/TD4/pom.xml
@@ -24,6 +24,31 @@
         </developer>
     </developers>
 
+    <repositories>
+        <repository>
+            <id>jboss-public-maven-repository</id>
+            <name>JBoss Public Maven Repository</name>
+            <url>https://repository.jboss.org/nexus/content/repositories/releases/</url>
+            <releases>
+                <enabled>true</enabled>
+                <updatePolicy>never</updatePolicy>
+            </releases>
+            <layout>default</layout>
+        </repository>
+    </repositories>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.wildfly.bom</groupId>
+                <artifactId>wildfly-ee-with-tools</artifactId>
+                <version>${version.wildfly-bom}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
@@ -46,6 +71,7 @@
         <version.apache-commons-codec>1.15</version.apache-commons-codec>
         <version.freemarker>2.3.30</version.freemarker>
         <version.resteasy>6.2.6.Final</version.resteasy>
+        <version.lombok>1.18.30</version.lombok>
     </properties>
 
     <dependencies>
@@ -86,6 +112,12 @@
             <artifactId>gson</artifactId>
             <version>2.8.9</version> <!-- Utilisez la dernière version disponible -->
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>${version.lombok}</version>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java b/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java
index a2c2b00b6f69a3779c8d7b4b2065b6ce795d4670..815732c2c58528d06e43019bd73323498a266a3c 100644
--- a/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java
+++ b/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java
@@ -1,8 +1,10 @@
 package fr.miage23.filestore.api;
 
+import jakarta.servlet.annotation.MultipartConfig;
 import jakarta.ws.rs.ApplicationPath;
 import jakarta.ws.rs.core.Application;
 
+@MultipartConfig // This annotation is needed to use multipart-form-data
 @ApplicationPath("api")
 public class FilestoreApplication extends Application {
 }
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/GETOutputNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/GETOutputNodeDto.java
deleted file mode 100644
index cecd4e528268790c856f938b8283748c4f12d682..0000000000000000000000000000000000000000
--- a/TD4/src/main/java/fr/miage23/filestore/api/dto/GETOutputNodeDto.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package fr.miage23.filestore.api.dto;
-
-import fr.miage23.filestore.TypeNode;
-
-public class GETOutputNodeDto {
-    private TypeNode type;
-    private String id;
-    private String parent;
-    private String name;
-    private long size;
-    private long creation;
-    private long modification;
-
-    public GETOutputNodeDto(TypeNode type, String id, String parent, String name, long size, long creation, long modification) {
-        this.type = type;
-        this.id = id;
-        this.parent = parent;
-        this.name = name;
-        this.size = size;
-        this.creation = creation;
-        this.modification = modification;
-    }
-}
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java
index c9233ddb0f4065ce4e13fe5e19ac6c7cd240033b..2b9976716ba6202ca414e26bfadeec6c3f59bae8 100644
--- a/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java
+++ b/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java
@@ -5,15 +5,19 @@ import jakarta.validation.constraints.Pattern;
 import jakarta.validation.constraints.Size;
 import jakarta.ws.rs.FormParam;
 import jakarta.ws.rs.core.MediaType;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 import org.jboss.resteasy.annotations.providers.multipart.PartType;
 
 import java.io.InputStream;
 
+@Data
+@NoArgsConstructor // Default constructor needed for JAX-RS
 public class InputNodeDto {
 
     @FormParam("name")
     @PartType(MediaType.TEXT_PLAIN)
-    @Filename
+    @Pattern(regexp = "^[^*&%/]+$")
     private String name;
     @FormParam("data")
     @PartType(MediaType.APPLICATION_OCTET_STREAM)
@@ -21,33 +25,5 @@ public class InputNodeDto {
     @Size(max=2000000, message="content size is 2Mo max, for larger content use a multipart-form-data with data parameter")
     private byte[] content;
 
-    public InputNodeDto() {
-        // Default constructor needed for JAX-RS
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public InputStream getData() {
-        return data;
-    }
-
-    public void setData(InputStream data) {
-        this.data = data;
-    }
-
-    public byte[] getContent() {
-        return content;
-    }
-
-    public void setContent(byte[] content) {
-        this.content = content;
-    }
-
 }
 
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/OutputNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/OutputNodeDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..2899cb3e0ce38732c1fccb1bc39c4860f42b7ef4
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/dto/OutputNodeDto.java
@@ -0,0 +1,17 @@
+package fr.miage23.filestore.api.dto;
+
+import fr.miage23.filestore.files.entity.TypeNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class OutputNodeDto {
+    private TypeNode type;
+    private String id;
+    private String parent;
+    private String name;
+    private long size;
+    private long creation;
+    private long modification;
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTOutputNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTOutputNodeDto.java
deleted file mode 100644
index 850577354ac9fc5b6b1bea17b4a4948fd4ef4f9f..0000000000000000000000000000000000000000
--- a/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTOutputNodeDto.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package fr.miage23.filestore.api.dto;
-
-import fr.miage23.filestore.TypeNode;
-
-public class POSTOutputNodeDto {
-
-    private String id = null;
-
-    public POSTOutputNodeDto(String id) {
-        this.id = id;
-    }
-}
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/mapper/NodeHtmlMapper.java b/TD4/src/main/java/fr/miage23/filestore/api/mapper/NodeHtmlMapper.java
deleted file mode 100644
index dd5cc3c5484e2f6a28391a1d6504e0fec22d5db9..0000000000000000000000000000000000000000
--- a/TD4/src/main/java/fr/miage23/filestore/api/mapper/NodeHtmlMapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package fr.miage23.filestore.api.mapper;
-
-import fr.miage23.filestore.files.entity.Node;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.ext.MessageBodyWriter;
-import jakarta.ws.rs.ext.Provider;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-
-@Provider
-@Produces(MediaType.TEXT_HTML)
-public class NodeHtmlMapper implements MessageBodyWriter<Node> {
-
-
-    @Override
-    public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
-        return true;
-    }
-
-    @Override
-    public void writeTo(Node node, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
-        Writer writer = new PrintWriter(outputStream);
-        writer.write("<html><head><title>Filestore</title></head>");
-        writer.write("<body><h2>" + node.getName() + "</h2>");
-        writer.write("<ul><li>id: " + node.getId() + "</li>");
-        writer.write("<li>type: " + node.getType() + "</li>");
-        writer.write("<li>size: " + node.getSize() + "</li>");
-        writer.write("<li>creation: " + node.getCreation() + "</li>");
-        writer.write("<li>modification: " + node.getModification() + "</li>");
-        writer.write("</ul></body>");
-        writer.flush();
-        writer.close();
-    }
-}
-
-
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java b/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java
index ceb58e8d9fd668b22d185be416a4b64ef7affce0..9a55b3caf0b52d7b51576ba4061e1771246f92a3 100644
--- a/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java
+++ b/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java
@@ -1,24 +1,17 @@
 package fr.miage23.filestore.api.resources;
 
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-import fr.miage23.filestore.TypeNode;
+import fr.miage23.filestore.auth.entity.Profile;
+import fr.miage23.filestore.files.entity.TypeNode;
 import fr.miage23.filestore.api.dto.CollectionDto;
-import fr.miage23.filestore.api.dto.GETNodeDto;
-import fr.miage23.filestore.api.dto.GETOutputNodeDto;
 import fr.miage23.filestore.api.dto.InputNodeDto;
-import fr.miage23.filestore.api.dto.POSTNodeDto;
-import fr.miage23.filestore.api.dto.POSTOutputNodeDto;
+import fr.miage23.filestore.api.template.Template;
+import fr.miage23.filestore.api.template.TemplateContent;
+import fr.miage23.filestore.config.FilestoreConfig;
 import fr.miage23.filestore.files.FileService;
 import fr.miage23.filestore.files.InMemoryFileServiceBean;
 import fr.miage23.filestore.files.entity.Node;
-import fr.miage23.filestore.files.exceptions.ContentException;
-import fr.miage23.filestore.files.exceptions.NodeAlreadyExistsException;
-import fr.miage23.filestore.files.exceptions.NodeNotFoundException;
-import fr.miage23.filestore.files.exceptions.NodeTypeException;
+import fr.miage23.filestore.files.exceptions.*;
+import jakarta.inject.Inject;
 import jakarta.validation.Valid;
 import jakarta.ws.rs.*;
 import jakarta.ws.rs.core.Context;
@@ -27,8 +20,13 @@ import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.UriInfo;
 import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
@@ -40,42 +38,38 @@ import java.util.stream.Collectors;
 @Path("nodes")
 public class NodesResource {
 
-    private FileService service = InMemoryFileServiceBean.getInstance();
     private static final Logger LOGGER = Logger.getLogger(NodesResource.class.getName());
-    @Context
-    UriInfo uriInfo; // Injectez l'objet UriInfo pour accéder aux informations d'URI.
 
-    /**
-     * Redirects to the default node ("/nodes/root").
-     *
-     * @return Response object for redirection to the default node.
-     */
+    private FileService service = InMemoryFileServiceBean.getInstance();
+    @Inject
+    private FilestoreConfig config;
+
     @GET
-    public Response redirectToDefaultNode() {
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response root(@Context UriInfo uriInfo) throws NodeNotFoundException {
         LOGGER.log(Level.INFO, "GET /api/nodes/root");
-        try {
-            Gson gson = new GsonBuilder()
-                    .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter())
-                    .create();
-            Node node = service.get("root");
-            return Response.ok(gson.toJson(
-                    (new GETOutputNodeDto(node.getType(), node.getId(), node.getParent(), node.getName(), node.getSize(), node.getCreation(), node.getModification())),
-                            GETOutputNodeDto.class),
-                    MediaType.APPLICATION_JSON).build();
-        } catch (NodeNotFoundException e) {
-            return Response.status(Response.Status.NOT_FOUND).entity("Node not found.").build();
-        }
+        Node node = service.get("");
+        URI root = uriInfo.getRequestUriBuilder().path(node.getId()).build();
+        return Response.seeOther(root).build();
+    }
+    @GET
+    @Produces(MediaType.TEXT_HTML)
+    public Response rootView(@Context UriInfo uriInfo) throws NodeNotFoundException {
+        LOGGER.log(Level.INFO, "GET /api/nodes (html)");
+        Node node = service.get("");
+        URI root = uriInfo.getRequestUriBuilder().path(node.getId()).path("content").build();
+        return Response.seeOther(root).build();
+    }
+
+    @GET
+    @Path("{id}")
+    @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
+    public Node getNode(@PathParam("id") String id) throws NodeNotFoundException {
+        LOGGER.log(Level.INFO, "GET /api/nodes/" + id);
+        Node node = service.get(id);
+        return node;
     }
 
-    /**
-     * Retrieves the content of a node identified by the given ID. For tree nodes, it returns a paginated
-     * list of child nodes. For blob nodes, it returns the binary content of the node.
-     *
-     * @param id      The ID of the node.
-     * @param limit   The maximum number of child nodes to return (default is 20).
-     * @param offset  The offset for pagination (default is 0).
-     * @return Response containing the content of the node or a paginated list of child nodes.
-     */
     @GET
     @Path("{id}/content")
     @Produces(MediaType.APPLICATION_JSON)
@@ -96,101 +90,80 @@ public class NodesResource {
         }
     }
 
-
-    /**
-     * Retrieves information about a specific node.
-     *
-     * @param id The ID of the node to retrieve.
-     * @return The Node object representing the requested node.
-     */
     @GET
-    @Path("{id}")
-    @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
-    public Response getNode(@PathParam("id") String id) throws NodeNotFoundException {
-        LOGGER.log(Level.INFO, "GET /api/nodes/" + id);
-        Gson gson = new GsonBuilder()
-                .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter())
-                .create();
+    @Path("{id}/content")
+    @Template(name = "files")
+    @Produces(MediaType.TEXT_HTML)
+    public Response contentView(@PathParam("id") final String id, @QueryParam("download") @DefaultValue("false") final boolean download) throws NodeNotFoundException, NodeTypeException, ContentException {
+        LOGGER.log(Level.INFO, "GET /api/nodes/" + id + "/content (html)");
         Node node = service.get(id);
-        return Response.ok(gson.toJson(
-                        (new GETOutputNodeDto(node.getType(), node.getId(), node.getParent(), node.getName(), node.getSize(), node.getCreation(), node.getModification())),
-                        GETOutputNodeDto.class),
-                MediaType.APPLICATION_JSON).build();
+        if (node.getType().equals(TypeNode.TREE)) {
+            TemplateContent<Map<String, Object>> content = new TemplateContent<>();
+            Map<String, Object> value = new HashMap<>();
+            value.put("ctx", config.instance().ctx());
+            value.put("profile", Profile.ANONYMOUS_PROFILE);
+            value.put("parent", node);
+            value.put("path", service.path(id));
+            value.put("nodes", service.list(id));
+            content.setContent(value);
+            return Response.ok(content).build();
+        } else {
+            return Response.ok(service.getContent(id))
+                    .header("Content-Type", node.getMimetype())
+                    .header("Content-Length", node.getSize())
+                    .header("Content-Disposition", ((download) ? "attachment; " : "") + "filename=" + node.getName()).build();
+        }
     }
 
-    /**
-     * Creates a new node with the provided parameters.
-     *
-     * @param id   The ID of the new node, input as a path parameter for a better url uses and transitions.
-     * @param name The name of the new node.
-     * @param info The UriInfo object to access URI information.
-     * @return Response object indicating the success or failure of the operation.
-     */
     @POST
     @Path("{id}")
-    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    public Response createNode(@PathParam("id") String id, @FormParam("name") String name, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException {
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response create(@PathParam("id") final String id, @Valid InputNodeDto dto, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException, ContentException {
         LOGGER.log(Level.INFO, "POST /api/nodes/" + id);
-        String newid;
-        if (name != null) {
-            newid = service.add(id, name);
+        String nid;
+        if (dto.getContent() != null) {
+            nid = service.add(id, dto.getName(), new ByteArrayInputStream(dto.getContent()));
         } else {
-            throw new IllegalArgumentException("A name must be provided");
+            nid = service.add(id, dto.getName());
         }
-        Gson gson = new GsonBuilder()
-                .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter())
-                .create();
-        Node node = service.get(newid);
-
-        return Response.ok(gson.toJson(
-                        (new POSTOutputNodeDto(node.getId())),
-                        POSTOutputNodeDto.class),
-                MediaType.APPLICATION_JSON).build();
+        URI createdUri = info.getBaseUriBuilder().path(NodesResource.class).path(nid).build();
+        return Response.created(createdUri).build();
     }
 
-    /**
-     * Creates a new node with the provided parameters and optionally uploads content.
-     *
-     * @param id   The ID of the new node.
-     * @param dto  The CreateNodeDto (DTO = Data Transfer Object) containing information about the new node.
-     * @param info The UriInfo object to access URI information.
-     * @return Response object indicating the success or failure of the operation.
-     */
     @POST
     @Path("{id}")
     @Produces(MediaType.TEXT_HTML)
     @Consumes(MediaType.MULTIPART_FORM_DATA)
-    public Response createView(@PathParam("id") final String id, @MultipartForm @Valid InputNodeDto dto, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException, ContentException {
+    public Response createView(@PathParam("id") final String id, @MultipartForm @Valid InputNodeDto dto, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException, ContentException, IOException {
         LOGGER.log(Level.INFO, "POST /api/nodes/" + id + " (html)");
-        String newid;
-        if (dto.getName() != null && dto.getData() != null){
-            newid = service.add(id, dto.getName(), dto.getData());
-        } else if (dto.getName() != null){
-            newid = service.add(id, dto.getName());
+        if (dto.getData() != null) {
+            service.add(id, dto.getName(), dto.getData());
         } else {
-            throw new IllegalArgumentException("A name must be provided");
+            service.add(id, dto.getName());
         }
-        Gson gson = new GsonBuilder()
-                .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter())
-                .create();
-        Node node = service.get(newid);
-        return Response.ok(gson.toJson(
-                        (new POSTOutputNodeDto(node.getId())),
-                        POSTOutputNodeDto.class),
-                MediaType.APPLICATION_JSON).build();
+        URI createdUri = info.getBaseUriBuilder().path(NodesResource.class).path(id).path("content").build();
+        return Response.seeOther(createdUri).build();
     }
 
-    // Classe EnumTypeAdapter pour la gestion de la sérialisation/désérialisation de l'énumération TypeNode
-    private static class EnumTypeAdapter extends TypeAdapter<TypeNode> {
-        @Override
-        public void write(JsonWriter out, TypeNode value) throws IOException {
-            out.value(value.name());
-        }
+    @PUT
+    @Path("{id}/{name}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    public Response update(@PathParam("id") final String id, @PathParam("name") String name, @FormParam("data") InputStream data) throws NodeNotEmptyException, NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException, ContentException {
+        LOGGER.log(Level.INFO, "PUT /api/nodes/" + id + "/" + name);
+        service.remove(id, name);
+        service.add(id, name, data);
+        return Response.noContent().build();
+    }
 
-        @Override
-        public TypeNode read(JsonReader in) throws IOException {
-            return TypeNode.valueOf(in.nextString());
-        }
+    @DELETE
+    @Path("{id}/{name}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response delete(@PathParam("id") final String id, @PathParam("name") final String name) throws NodeNotEmptyException, NodeNotFoundException, NodeTypeException {
+        LOGGER.log(Level.INFO, "DELETE /api/nodes/" + name);
+        service.remove(id, name);
+        return Response.noContent().build();
     }
 
 }
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java b/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java
index 8b6ef2b5c99690a91066af00de6d4de548aa6c01..465b82b0dc3a484740d39c992ccaaba7754f91c2 100644
--- a/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java
+++ b/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java
@@ -1,7 +1,6 @@
 package fr.miage23.filestore.api.validation;
 
 public class ValidationPattern {
-    // On interdit les caractères interdits par windows dans les noms de fichiers
-    public static final String FILE_PATTERN = "^[^\\/:*?\"<>|]+$";
+    public static final String FILE_PATTERN = "^[^*&%/\\~]+$";
 }
 
diff --git a/TD4/src/main/java/fr/miage23/filestore/auth/AuthenticationService.java b/TD4/src/main/java/fr/miage23/filestore/auth/AuthenticationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..9330f030cb7fc40553582e00e1365e8df09c8cdf
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/auth/AuthenticationService.java
@@ -0,0 +1,16 @@
+package fr.miage23.filestore.auth;
+
+import fr.miage23.filestore.auth.entity.Profile;
+
+public interface AuthenticationService {
+
+    String UNAUTHENTIFIED_IDENTIFIER = "anonymous";
+
+    boolean isAuthentified();
+
+    String getConnectedIdentifier();
+
+    Profile getConnectedProfile();
+
+}
+
diff --git a/TD4/src/main/java/fr/miage23/filestore/auth/entity/Profile.java b/TD4/src/main/java/fr/miage23/filestore/auth/entity/Profile.java
new file mode 100644
index 0000000000000000000000000000000000000000..030ce5546e074d78e1bbe9bdb941311fcd136c78
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/auth/entity/Profile.java
@@ -0,0 +1,80 @@
+package fr.miage23.filestore.auth.entity;
+
+import fr.miage23.filestore.auth.AuthenticationService;
+import org.apache.commons.codec.digest.DigestUtils;
+
+public class Profile {
+
+    public static final Profile ANONYMOUS_PROFILE = new Profile(AuthenticationService.UNAUTHENTIFIED_IDENTIFIER, "anonymous", "Anonymous User", "user@anonymous.org", false);
+
+    private String id;
+    private String username;
+    private String fullname;
+    private String email;
+    private boolean owner;
+
+    public Profile() {
+    }
+
+    public Profile(String id, String username, String fullname, String email, boolean owner) {
+        this.id = id;
+        this.username = username;
+        this.fullname = fullname;
+        this.email = email;
+        this.owner = owner;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getFullname() {
+        return fullname;
+    }
+
+    public void setFullname(String fullname) {
+        this.fullname = fullname;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getGravatarHash() {
+        return DigestUtils.md5Hex(email);
+    }
+
+    public boolean isOwner() {
+        return owner;
+    }
+
+    public void setOwner(boolean owner) {
+        this.owner = owner;
+    }
+
+    @Override
+    public String toString() {
+        return "Profile{" +
+                "id='" + id + '\'' +
+                ", username='" + username + '\'' +
+                ", fullname='" + fullname + '\'' +
+                ", email='" + email + '\'' +
+                '}';
+    }
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/config/FilestoreConfig.java b/TD4/src/main/java/fr/miage23/filestore/config/FilestoreConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf4e7cab05f14dec3d7ae9f78d0a87b26fc1db36
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/config/FilestoreConfig.java
@@ -0,0 +1,25 @@
+package fr.miage23.filestore.config;
+
+import java.nio.file.Path;
+
+public interface FilestoreConfig {
+
+    String owner();
+
+    Path home();
+
+    InstanceConfig instance();
+
+    interface InstanceConfig {
+
+        boolean https();
+
+        String host();
+
+        int port();
+
+        String ctx();
+
+    }
+
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/config/FilestoreConfigBean.java b/TD4/src/main/java/fr/miage23/filestore/config/FilestoreConfigBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5f23fc53b3447a764db81cb7ded5c4f4012ae67
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/config/FilestoreConfigBean.java
@@ -0,0 +1,119 @@
+package fr.miage23.filestore.config;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@ApplicationScoped
+public class FilestoreConfigBean implements FilestoreConfig {
+
+    private static final Logger LOGGER = Logger.getLogger(FilestoreConfig.class.getName());
+
+    private Path home;
+    private String owner;
+    private LocalInstanceConfig instance;
+
+    public FilestoreConfigBean() {
+    }
+
+    @PostConstruct
+    public void init() {
+        LOGGER.log(Level.INFO, "Initializing config");
+        home = Paths.get(getConfigValue("filestoreHome", System.getProperty("user.home").concat(File.separator).concat(".filestore")));
+        LOGGER.log(Level.INFO, "home set to: " + home);
+        owner = getConfigValue("filestoreOwner", "admin");
+        LOGGER.log(Level.INFO, "owner set to: " + owner);
+        instance = new LocalInstanceConfig(Boolean.getBoolean(getConfigValue("filestoreHttps", "false")),
+                getConfigValue("filestoreHost", "localhost"),
+                Integer.parseInt(getConfigValue("filestorePort", "8080")),
+                getConfigValue("filestoreCtx", "/filestore"));
+        LOGGER.log(Level.INFO, "instance set to: " + instance);
+    }
+
+    @Override
+    public InstanceConfig instance() {
+        return instance;
+    }
+
+    @Override
+    public Path home() {
+        return home;
+    }
+
+    @Override
+    public String owner() {
+        return owner;
+    }
+
+    static class LocalInstanceConfig implements InstanceConfig {
+
+        private boolean https;
+        private String host;
+        private int port;
+
+        private String ctx;
+
+        public LocalInstanceConfig(boolean https, String host, int port, String ctx) {
+            this.https = https;
+            this.host = host;
+            this.port = port;
+            this.ctx = ctx;
+        }
+
+        @Override
+        public boolean https() {
+            return https;
+        }
+
+        @Override
+        public String host() {
+            return host;
+        }
+
+        @Override
+        public int port() {
+            return port;
+        }
+
+        @Override
+        public String ctx() {
+            return ctx;
+        }
+
+        @Override
+        public String toString() {
+            return "LocalInstanceConfig{" +
+                    "https=" + https +
+                    ", host='" + host + '\'' +
+                    ", port=" + port +
+                    ", ctx='" + ctx + '\'' +
+                    '}';
+        }
+    }
+
+    private String getConfigValue(String key, String defaultValue) {
+        if ( System.getenv(camelToEnv(key)) != null ) {
+            LOGGER.log(Level.FINE, "config value loaded from system environment: " + System.getenv(camelToEnv(key)));
+            return System.getenv(camelToEnv(key));
+        } else if ( System.getProperty(camelToProp(key)) != null ) {
+            LOGGER.log(Level.FINE, "config value loaded from system java property: " + System.getProperty(camelToProp(key)));
+            return System.getProperty(camelToProp(key));
+        } else {
+            LOGGER.log(Level.FINE, "config value default: " + defaultValue);
+            return defaultValue;
+        }
+    }
+
+    private static String camelToEnv(String var) {
+        return var.replaceAll("([a-z])([A-Z]+)", "$1_$2").toUpperCase();
+    }
+
+    private static String camelToProp(String var) {
+        return var.replaceAll("([a-z])([A-Z]+)", "$1.$2").toLowerCase();
+    }
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/FileService.java b/TD4/src/main/java/fr/miage23/filestore/files/FileService.java
index cd636788f98bc3c3ad43c182626f146496c78f6d..13354663ee3a98529f85665c59c8a2492e241e53 100644
--- a/TD4/src/main/java/fr/miage23/filestore/files/FileService.java
+++ b/TD4/src/main/java/fr/miage23/filestore/files/FileService.java
@@ -13,6 +13,8 @@ public interface FileService {
 
     List<Node> list(String id) throws NodeNotFoundException;
 
+    List<Node> path(String id) throws NodeNotFoundException;
+
     Node get(String id) throws NodeNotFoundException;
 
     InputStream getContent(String id) throws NodeNotFoundException, NodeTypeException, ContentException;
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java b/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java
index dad5d5d42bb8f5b8a4001918bfcb73565469a074..9a92edbe5de060975c139747785ffa0b1687fdb8 100644
--- a/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java
+++ b/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java
@@ -1,7 +1,7 @@
 package fr.miage23.filestore.files;
 
-import fr.miage23.filestore.TypeNode;
 import fr.miage23.filestore.files.entity.Node;
+import fr.miage23.filestore.files.entity.TypeNode;
 import fr.miage23.filestore.files.exceptions.*;
 
 import java.io.ByteArrayInputStream;
@@ -46,13 +46,32 @@ public class InMemoryFileServiceBean implements FileService {
         return nodes.values().stream().filter(n -> n.getParent().equals(pid)).collect(Collectors.toList());
     }
 
+    @Override
+    public List<Node> path(String id) throws NodeNotFoundException {
+        LOGGER.log(Level.FINE, "Get path for node with id: " + id);
+        List<Node> path = new ArrayList<>();
+        while (!id.equals(ROOT_NODE_ID)) {
+            if (!nodes.containsKey(id)) {
+                throw new NodeNotFoundException("unable to find a node with id " + id + " in the storage");
+            }
+            Node node = nodes.get(id);
+            path.add(node);
+            id = node.getParent();
+        }
+        Collections.reverse(path);
+        LOGGER.log(Level.FINE, "path: " + path.stream().map(Node::getName).collect(Collectors.joining(" > ")));
+        return path;
+    }
+
+
     @Override
     public Node get(String id) throws NodeNotFoundException {
-        LOGGER.log(Level.INFO, "Getting node with id: " + id);
-        if (!nodes.containsKey(id)) {
-            throw new NodeNotFoundException("unable to find a node with id " + id + " in the storage");
+        String pid = (id == null || id.isEmpty())? ROOT_NODE_ID:id;
+        LOGGER.log(Level.INFO, "Getting node with id: " + pid);
+        if (!nodes.containsKey(pid)) {
+            throw new NodeNotFoundException("unable to find a node with id " + pid + " in the storage");
         }
-        return nodes.get(id);
+        return nodes.get(pid);
     }
 
     @Override
@@ -86,6 +105,7 @@ public class InMemoryFileServiceBean implements FileService {
             throw new NodeAlreadyExistsException("A node with name: " + name + " already exists in tree with id: " + pid);
         }
         Node node = new Node(TypeNode.TREE, pid, UUID.randomUUID().toString(), name);
+        node.setMimetype(TREE_NODE_MIMETYPE);
         nodes.put(node.getId(), node);
         pnode.setSize(pnode.getSize()+1);
         return node.getId();
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java b/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java
index f30d814c1653df08b0f0374065378dd787ea8fe2..011ce4095ee14dc44a32887779074d4f63407744 100644
--- a/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java
+++ b/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java
@@ -1,12 +1,13 @@
 package fr.miage23.filestore.files.entity;
 
-import fr.miage23.filestore.TypeNode;
 import fr.miage23.filestore.files.FileService;
+import lombok.Data;
 
 import java.io.Serializable;
 import java.util.Comparator;
 import java.util.Objects;
 
+@Data
 public class Node implements Comparable<Node>, Serializable {
 
     private TypeNode type;
@@ -33,86 +34,6 @@ public class Node implements Comparable<Node>, Serializable {
         this.name = name;
     }
 
-    public TypeNode getType() {
-        return type;
-    }
-
-    public void setType(TypeNode type) {
-        this.type = type;
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-    public long getVersion() {
-        return version;
-    }
-
-    public void setVersion(long version) {
-        this.version = version;
-    }
-
-    public String getParent() {
-        return parent;
-    }
-
-    public void setParent(String parent) {
-        this.parent = parent;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getContent() {
-        return content;
-    }
-
-    public void setContent(String content) {
-        this.content = content;
-    }
-
-    public String getMimetype() {
-        return mimetype;
-    }
-
-    public void setMimetype(String mimetype) {
-        this.mimetype = mimetype;
-    }
-
-    public long getSize() {
-        return size;
-    }
-
-    public void setSize(long size) {
-        this.size = size;
-    }
-
-    public long getCreation() {
-        return creation;
-    }
-
-    public void setCreation(long creation) {
-        this.creation = creation;
-    }
-
-    public long getModification() {
-        return modification;
-    }
-
-    public void setModification(long modification) {
-        this.modification = modification;
-    }
-
     public boolean isRoot() {
         return this.id.equals(FileService.ROOT_NODE_ID);
     }
@@ -121,7 +42,6 @@ public class Node implements Comparable<Node>, Serializable {
         return this.type.equals(TypeNode.TREE);
     }
 
-
     @Override
     public int compareTo(Node o) {
         if (this.getType().equals(o.getType())) {
@@ -146,6 +66,22 @@ public class Node implements Comparable<Node>, Serializable {
         return Objects.hash(type, id, name, content, mimetype, creation, modification);
     }
 
+    @Override
+    public String toString() {
+        return "Node{" +
+                "type=" + type +
+                ", id='" + id + '\'' +
+                ", version=" + version +
+                ", parent='" + parent + '\'' +
+                ", name='" + name + '\'' +
+                ", mimetype='" + mimetype + '\'' +
+                ", size=" + size +
+                ", creation=" + creation +
+                ", modification=" + modification +
+                ", content='" + content + '\'' +
+                '}';
+    }
+
     public static class NameComparatorAsc implements Comparator<Node> {
         @Override
         public int compare(Node o1, Node o2) {
diff --git a/TD4/src/main/java/fr/miage23/filestore/TypeNode.java b/TD4/src/main/java/fr/miage23/filestore/files/entity/TypeNode.java
similarity index 51%
rename from TD4/src/main/java/fr/miage23/filestore/TypeNode.java
rename to TD4/src/main/java/fr/miage23/filestore/files/entity/TypeNode.java
index d03f39dbf35208aaf0029af778d532bf5b2a7f2a..5f235677f04a28be9839fcfa7e7da269b9581dae 100644
--- a/TD4/src/main/java/fr/miage23/filestore/TypeNode.java
+++ b/TD4/src/main/java/fr/miage23/filestore/files/entity/TypeNode.java
@@ -1,4 +1,4 @@
-package fr.miage23.filestore;
+package fr.miage23.filestore.files.entity;
 
 public enum TypeNode {
     TREE,
diff --git a/TD4/src/main/resources/ValidationMessages.properties b/TD4/src/main/resources/ValidationMessages.properties
index dc0d43f4b21944c4c8ec8b96edc56ee4fbc56c0f..a58bc6359acb30ffa67e0ccf9b6d735185ef54da 100644
--- a/TD4/src/main/resources/ValidationMessages.properties
+++ b/TD4/src/main/resources/ValidationMessages.properties
@@ -1 +1 @@
-invalid.filename=The filename contains forbidden characters
+invalid.filename=Le nom du fichier contient des caract�res interdits