Skip to content

Instantly share code, notes, and snippets.

@Nithanim
Created February 8, 2026 19:44
Show Gist options
  • Select an option

  • Save Nithanim/1c863f25c570e64da99bb885f592723a to your computer and use it in GitHub Desktop.

Select an option

Save Nithanim/1c863f25c570e64da99bb885f592723a to your computer and use it in GitHub Desktop.
webdav

Yes, you can definitely integrate Jackrabbit Oak with Quarkus! Here's how:

1. Quarkus Integration Setup

Dependencies (pom.xml):

<dependencies>
    <dependency>
        <groupId>org.apache.jackrabbit</groupId>
        <artifactId>jackrabbit-oak-core</artifactId>
        <version>1.44.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.jackrabbit</groupId>
        <artifactId>jackrabbit-oak-jcr</artifactId>
        <version>1.44.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.jackrabbit</groupId>
        <artifactId>jackrabbit-webdav</artifactId>
        <version>2.20.0</version>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
</dependencies>

2. Configuration Service

@ApplicationScoped
public class OakRepositoryConfig {
    
    @ConfigProperty(name = "webdav.root.path")
    String rootPath;
    
    @ConfigProperty(name = "webdav.repository.path")
    String repositoryPath;
    
    public Repository createRepository() throws Exception {
        // Create Oak repository with filesystem backend
        FileSystem fs = new LocalFileSystem(new File(repositoryPath));
        org.apache.jackrabbit.oak.api.CommitHook commitHook = 
            new org.apache.jackrabbit.oak.spi.commit.CommitHooks();
        
        NodeStore nodeStore = new SegmentNodeStore(
            new SegmentBlobStore(new SegmentWriter(fs)));
        
        return new Jcr(nodeStore).createRepository();
    }
}

3. WebDAV Endpoint Service

@Path("/webdav")
@ApplicationScoped
public class WebDavResource {
    
    @Inject
    Repository repository;
    
    @GET
    @Path("{*path}")
    public Response handleWebDavGet(
            @PathParam("path") String path,
            @Context HttpServletRequest request) {
        // Handle WebDAV GET requests
        return Response.ok().build();
    }
    
    @POST
    @Path("{*path}")
    public Response handleWebDavPost(
            @PathParam("path") String path,
            InputStream inputStream,
            @Context HttpServletRequest request) {
        // Handle WebDAV POST requests
        return Response.ok().build();
    }
}

4. Quarkus Configuration

application.properties:

# WebDAV Configuration
webdav.root.path=/var/webdav
webdav.repository.path=/var/jackrabbit-repo
webdav.port=8080

# Security
quarkus.http.auth.basic=true
quarkus.http.auth.proactive=true

5. Security Implementation

Custom Security Filter:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class WebDavSecurityFilter implements ContainerRequestFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        String authHeader = requestContext.getHeaderString("Authorization");
        
        if (authHeader == null || !authHeader.startsWith("Basic ")) {
            requestContext.abortWith(
                Response.status(Response.Status.UNAUTHORIZED)
                       .header("WWW-Authenticate", "Basic realm=\"WebDAV\"")
                       .build());
            return;
        }
        
        // Validate credentials against your security store
        String credentials = authHeader.substring(6);
        String decoded = new String(Base64.getDecoder().decode(credentials));
        String[] parts = decoded.split(":", 2);
        
        if (!validateUser(parts[0], parts[1])) {
            requestContext.abortWith(
                Response.status(Response.Status.UNAUTHORIZED)
                       .build());
        }
    }
    
    private boolean validateUser(String username, String password) {
        // Implement your authentication logic
        // Could be LDAP, database, or custom user store
        return true; // Simplified for example
    }
}

6. Complete Quarkus Extension

@Singleton
public class OakWebDavExtension {
    
    private Repository repository;
    private WebDAVServlet webdavServlet;
    
    @PostConstruct
    public void initialize() throws Exception {
        // Initialize Oak repository
        File repoDir = new File("/tmp/jackrabbit-oak");
        if (!repoDir.exists()) {
            repoDir.mkdirs();
        }
        
        // Create repository with filesystem backend
        RepositoryBuilder builder = RepositoryBuilder.newInstance();
        builder.setFileSystem(new LocalFileSystem(repoDir));
        repository = builder.build();
        
        // Setup WebDAV servlet
        webdavServlet = new WebDAVServlet();
        webdavServlet.init(new ServletConfig() {
            @Override
            public String getServletName() { return "WebDAV"; }
            @Override
            public ServletContext getServletContext() { return null; }
            @Override
            public String getInitParameter(String name) { 
                return "jcr.repository"; 
            }
            @Override
            public Enumeration<String> getInitParameterNames() {
                return Collections.enumeration(Collections.singletonList("jcr.repository"));
            }
        });
    }
}

Security Architecture

1. Authentication Methods:

  • Basic Authentication (via HTTP headers)
  • Digest Authentication
  • Custom authentication providers
  • Integration with existing security frameworks (LDAP, OAuth)

2. Authorization:

// Example with custom access control
public class WebDavAccessControl {
    
    public boolean canRead(String user, String path) {
        // Check permissions based on user roles
        return true; // Simplified
    }
    
    public boolean canWrite(String user, String path) {
        // Check write permissions
        return user.equals("admin"); // Simplified
    }
}

3. Role-Based Access Control:

@ApplicationScoped
public class RoleBasedAccessControl {
    
    private Map<String, Set<String>> userRoles = new HashMap<>();
    
    public boolean hasPermission(String user, String path, String permission) {
        Set<String> roles = userRoles.get(user);
        if (roles == null) return false;
        
        // Check if user has required role for path
        return roles.contains(permission);
    }
}

4. Integration with Quarkus Security:

@ApplicationScoped
public class QuarkusWebDavSecurity {
    
    @Inject
    SecurityIdentity securityIdentity;
    
    public boolean isAuthenticated() {
        return securityIdentity.isAnonymous();
    }
    
    public String getCurrentUser() {
        return securityIdentity.getPrincipal().getName();
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment