From 742bcef8585fcc59dd636105742b6f04b2807b16 Mon Sep 17 00:00:00 2001 From: Kruti Shah Date: Wed, 14 Jan 2026 17:37:15 +0000 Subject: [PATCH 1/4] ISSUE-33 (#96) (#98) ## Description - db integration Co-authored-by: hitanshu310 Co-authored-by: = <=> Co-authored-by: Kruti Shah Reviewed-on: https://gitea.hithomelabs.com/Hithomelabs/CFTunnels/pulls/96 Co-authored-by: Kruti Shah Co-committed-by: Kruti Shah Reviewed-on: https://gitea.hithomelabs.com/Hithomelabs/CFTunnels/pulls/98 Reviewed-by: hitanshu Co-authored-by: Kruti Shah Co-committed-by: Kruti Shah --- build.gradle | 1 + .../Controllers/TunnelController.java | 15 ++++ .../hithomelabs/CFTunnels/Entity/Mapping.java | 34 +++++++++ .../hithomelabs/CFTunnels/Entity/Request.java | 45 ++++++++++++ .../hithomelabs/CFTunnels/Entity/Tunnel.java | 29 ++++++++ .../hithomelabs/CFTunnels/Entity/User.java | 30 ++++++++ .../Repositories/MappingRepository.java | 11 +++ .../Repositories/RequestRepository.java | 11 +++ .../Repositories/TunnelRepository.java | 13 ++++ .../Repositories/UserRepository.java | 14 ++++ .../Services/MappingRequestService.java | 71 +++++++++++++++++++ .../resources/application-test.properties | 8 ++- src/main/resources/schema.sql | 56 +++++++-------- .../Controllers/TunnelControllerTest.java | 4 ++ 14 files changed, 309 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Entity/Mapping.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Entity/Request.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Entity/Tunnel.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Entity/User.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Repositories/MappingRepository.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Repositories/RequestRepository.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Repositories/TunnelRepository.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Repositories/UserRepository.java create mode 100644 src/main/java/com/hithomelabs/CFTunnels/Services/MappingRequestService.java diff --git a/build.gradle b/build.gradle index 0800341..90dc143 100644 --- a/build.gradle +++ b/build.gradle @@ -54,6 +54,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'org.postgresql:postgresql' implementation 'org.hibernate.validator:hibernate-validator' + runtimeOnly 'com.h2database:h2' } tasks.named('test') { diff --git a/src/main/java/com/hithomelabs/CFTunnels/Controllers/TunnelController.java b/src/main/java/com/hithomelabs/CFTunnels/Controllers/TunnelController.java index 3362a83..53fb4f9 100644 --- a/src/main/java/com/hithomelabs/CFTunnels/Controllers/TunnelController.java +++ b/src/main/java/com/hithomelabs/CFTunnels/Controllers/TunnelController.java @@ -4,11 +4,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.hithomelabs.CFTunnels.Config.AuthoritiesToGroupMapping; import com.hithomelabs.CFTunnels.Config.CloudflareConfig; import com.hithomelabs.CFTunnels.Config.RestTemplateConfig; +import com.hithomelabs.CFTunnels.Entity.Request; import com.hithomelabs.CFTunnels.Headers.AuthKeyEmailHeader; import com.hithomelabs.CFTunnels.Models.Config; import com.hithomelabs.CFTunnels.Models.Ingress; import com.hithomelabs.CFTunnels.Models.TunnelResponse; import com.hithomelabs.CFTunnels.Services.CloudflareAPIService; +import com.hithomelabs.CFTunnels.Services.MappingRequestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.*; @@ -44,6 +46,9 @@ public class TunnelController implements ErrorController { @Autowired CloudflareAPIService cloudflareAPIService; + @Autowired + MappingRequestService mappingRequestService; + @PreAuthorize("hasAnyRole('USER')") @GetMapping("/whoami") public Map whoAmI(@AuthenticationPrincipal OidcUser oidcUser) { @@ -132,4 +137,14 @@ public class TunnelController implements ErrorController { return ResponseEntity.ok(jsonResponse); } + + @PreAuthorize("hasAnyRole('DEVELOPER')") + @PutMapping("/tunnel/{tunnelId}/request") + public ResponseEntity createTunnelMappingRequest(@PathVariable String tunnelId, @AuthenticationPrincipal OidcUser oidcUser, @RequestBody Ingress ingess){ + Request request = mappingRequestService.createMappingRequest(tunnelId, ingess, oidcUser); + if(request.getId() != null) + return ResponseEntity.status(HttpStatus.CREATED).body(request); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } diff --git a/src/main/java/com/hithomelabs/CFTunnels/Entity/Mapping.java b/src/main/java/com/hithomelabs/CFTunnels/Entity/Mapping.java new file mode 100644 index 0000000..0081205 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Entity/Mapping.java @@ -0,0 +1,34 @@ +package com.hithomelabs.CFTunnels.Entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + + +import java.util.UUID; + +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "mappings") +public class Mapping { + + @Id + @GeneratedValue + @Column(columnDefinition = "uuid", nullable = false, unique = true) + private UUID id; + + @Column(nullable = false) + private int port; + + @Column(length = 50, nullable = false) + private String subdomain; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "tunnel_id", nullable = false) + private Tunnel tunnel; +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Entity/Request.java b/src/main/java/com/hithomelabs/CFTunnels/Entity/Request.java new file mode 100644 index 0000000..8d73de8 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Entity/Request.java @@ -0,0 +1,45 @@ +package com.hithomelabs.CFTunnels.Entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "requests") +public class Request { + + @Id + @GeneratedValue + @Column(columnDefinition = "uuid", unique = true, nullable = false) + private UUID id; + + @OneToOne + @JoinColumn(name = "mapping_id", unique = true, nullable = false) + private Mapping mapping; + + @ManyToOne + @JoinColumn(name = "created_by", nullable = false) + private User createdBy; + + @ManyToOne + @JoinColumn(name = "accepted_by") + private User acceptedBy; + + public enum RequestStatus { + PENDING, + APPROVED, + REJECTED + } + + @Enumerated(EnumType.STRING) + @Column(length = 10, nullable = false) + private RequestStatus status; +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Entity/Tunnel.java b/src/main/java/com/hithomelabs/CFTunnels/Entity/Tunnel.java new file mode 100644 index 0000000..9c56663 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Entity/Tunnel.java @@ -0,0 +1,29 @@ +package com.hithomelabs.CFTunnels.Entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Table(name="tunnels") +public class Tunnel { + + @Id + @GeneratedValue + @Column(columnDefinition = "uuid", insertable = false, updatable = false, nullable = false) + private UUID id; + + @Column(length = 10, unique = true, nullable = false) + private String environment; + + @Column(name = "cf_tunnel_id", columnDefinition = "uuid", unique = true, nullable = false) + private UUID cfTunnelId; +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Entity/User.java b/src/main/java/com/hithomelabs/CFTunnels/Entity/User.java new file mode 100644 index 0000000..5783357 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Entity/User.java @@ -0,0 +1,30 @@ +package com.hithomelabs.CFTunnels.Entity; +import jakarta.persistence.*; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "users") +public class User { + @Id + @GeneratedValue + @Column(columnDefinition = "uuid", insertable = false, updatable = false, nullable = false) + private UUID id; + + @Column(length = 50, nullable = false) + @Size(max = 50) + private String name; + + @Column(length = 50, nullable = false) + @Size(max = 50) + private String email; +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Repositories/MappingRepository.java b/src/main/java/com/hithomelabs/CFTunnels/Repositories/MappingRepository.java new file mode 100644 index 0000000..73b469c --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Repositories/MappingRepository.java @@ -0,0 +1,11 @@ +package com.hithomelabs.CFTunnels.Repositories; + +import com.hithomelabs.CFTunnels.Entity.Mapping; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface MappingRepository extends JpaRepository { +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Repositories/RequestRepository.java b/src/main/java/com/hithomelabs/CFTunnels/Repositories/RequestRepository.java new file mode 100644 index 0000000..fe79625 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Repositories/RequestRepository.java @@ -0,0 +1,11 @@ +package com.hithomelabs.CFTunnels.Repositories; + +import com.hithomelabs.CFTunnels.Entity.Request; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface RequestRepository extends JpaRepository { +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Repositories/TunnelRepository.java b/src/main/java/com/hithomelabs/CFTunnels/Repositories/TunnelRepository.java new file mode 100644 index 0000000..178f44e --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Repositories/TunnelRepository.java @@ -0,0 +1,13 @@ +package com.hithomelabs.CFTunnels.Repositories; + +import com.hithomelabs.CFTunnels.Entity.Tunnel; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface TunnelRepository extends JpaRepository { + Optional findByCfTunnelId(UUID cfTunnelId); +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Repositories/UserRepository.java b/src/main/java/com/hithomelabs/CFTunnels/Repositories/UserRepository.java new file mode 100644 index 0000000..a1038a7 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Repositories/UserRepository.java @@ -0,0 +1,14 @@ +package com.hithomelabs.CFTunnels.Repositories; + +import com.hithomelabs.CFTunnels.Entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface UserRepository extends JpaRepository { + + Optional findByEmail(String email); +} diff --git a/src/main/java/com/hithomelabs/CFTunnels/Services/MappingRequestService.java b/src/main/java/com/hithomelabs/CFTunnels/Services/MappingRequestService.java new file mode 100644 index 0000000..d026f65 --- /dev/null +++ b/src/main/java/com/hithomelabs/CFTunnels/Services/MappingRequestService.java @@ -0,0 +1,71 @@ +package com.hithomelabs.CFTunnels.Services; + +import com.hithomelabs.CFTunnels.Entity.Mapping; +import com.hithomelabs.CFTunnels.Entity.Request; +import com.hithomelabs.CFTunnels.Entity.Tunnel; +import com.hithomelabs.CFTunnels.Entity.User; +import com.hithomelabs.CFTunnels.Models.Ingress; +import com.hithomelabs.CFTunnels.Repositories.MappingRepository; +import com.hithomelabs.CFTunnels.Repositories.RequestRepository; +import com.hithomelabs.CFTunnels.Repositories.TunnelRepository; +import com.hithomelabs.CFTunnels.Repositories.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.UUID; + +@Service +public class MappingRequestService { + + @Autowired + UserRepository userRepository; + + @Autowired + MappingRepository mappingRepository; + + @Autowired + RequestRepository requestRepository; + + @Autowired + TunnelRepository tunnelRepository; + + public Mapping createMapping(UUID tunnelId, Ingress ingress){ + Tunnel tunnel = tunnelRepository.findByCfTunnelId(tunnelId).orElseThrow(() -> new RuntimeException("Tunnel not found")); + Mapping mapping = createMappingFromTunnelIngress(tunnel, ingress); + return mappingRepository.save(mapping); + } + + public Request createRequest(Mapping mapping, User user){ + Request request = new Request(); + request.setMapping(mapping); + request.setCreatedBy(user); + request.setStatus(Request.RequestStatus.PENDING); + return requestRepository.save(request); + } + + public Request createMappingRequest(String tunnelId, Ingress ingress, OidcUser oidcUser){ + User user = userRepository.findByEmail(oidcUser.getEmail()).orElseGet(()-> mapUser(oidcUser)); + Mapping mapping = createMapping(UUID.fromString(tunnelId), ingress); + return createRequest(mapping, user); + } + + public User mapUser(OidcUser oidcUser){ + String email = oidcUser.getEmail(); + String name = oidcUser.getNickName(); + User user = new User(); + user.setEmail(email); + user.setName(name); + userRepository.save(user); + return user; + } + + public Mapping createMappingFromTunnelIngress(Tunnel tunnel, Ingress ingress){ + Mapping mapping = new Mapping(); + mapping.setTunnel(tunnel); + mapping.setPort(Integer.parseInt(ingress.getService().split(":")[2])); + mapping.setSubdomain(ingress.getHostname().split("\\.")[0]); + return mapping; + } +} diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index e5c014b..a0ccff7 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1 +1,7 @@ -api.baseUrl=https://testcf.hithomelabs.com \ No newline at end of file +api.baseUrl=https://testcf.hithomelabs.com + +spring.datasource.url: jdbc:h2:mem:testdb +spring.datasource.driver-class-name: org.h2.Driver +spring.datasource.username: sa +spring.datasource.password: +spring.datasource.jpa.hibernate.ddl-auto: none \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 1fa876d..368b406 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,37 +1,29 @@ --- schema.sql +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; --- Roles table -CREATE TABLE IF NOT EXISTS roles ( - role_id SERIAL PRIMARY KEY, - role_name VARCHAR(50) UNIQUE NOT NULL -); - --- Users table -CREATE TABLE IF NOT EXISTS users ( - user_id SERIAL PRIMARY KEY, - user_name VARCHAR(100) NOT NULL, - password VARCHAR(255) NOT NULL -); - --- User-Role Mapping table (many-to-many relationship) -CREATE TABLE IF NOT EXISTS user_role_mapping ( - mapping_id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, - role_id INTEGER NOT NULL REFERENCES roles(role_id) ON DELETE CASCADE -); - --- Tunnels table CREATE TABLE IF NOT EXISTS tunnels ( - tunnel_id SERIAL PRIMARY KEY, - tunnel_name VARCHAR(100) NOT NULL, - tunnel_type VARCHAR(50) NOT NULL + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + environment VARCHAR(10) NOT NULL, + cf_tunnel_id UUID UNIQUE NOT NULL ); --- Mapping Requests table -CREATE TABLE IF NOT EXISTS mapping_requests ( - request_id SERIAL PRIMARY KEY, - request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - status VARCHAR(20) NOT NULL, - user_id INTEGER REFERENCES users(user_id) ON DELETE SET NULL, - tunnel_id INTEGER REFERENCES tunnels(tunnel_id) ON DELETE SET NULL +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(50) NOT NULL ); + +CREATE TABLE IF NOT EXISTS mappings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + tunnel_id UUID NOT NULL REFERENCES tunnels(id) ON DELETE CASCADE, + port INT NOT NULL, + subdomain VARCHAR(50) NOT NULL +-- UNIQUE (tunnel_id, port), +-- UNIQUE (tunnel_id, subdomain) +); + +CREATE TABLE IF NOT EXISTS requests ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + mapping_id UUID NOT NULL REFERENCES mappings(id) ON DELETE CASCADE, + created_by UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT, + accepted_by UUID REFERENCES users(id) ON DELETE SET NULL, + status VARCHAR(20) NOT NULL CHECK (status IN ('PENDING', 'APPROVED', 'REJECTED')) +); \ No newline at end of file diff --git a/src/test/java/com/hithomelabs/CFTunnels/Controllers/TunnelControllerTest.java b/src/test/java/com/hithomelabs/CFTunnels/Controllers/TunnelControllerTest.java index 644288e..ff7d303 100644 --- a/src/test/java/com/hithomelabs/CFTunnels/Controllers/TunnelControllerTest.java +++ b/src/test/java/com/hithomelabs/CFTunnels/Controllers/TunnelControllerTest.java @@ -10,6 +10,7 @@ import com.hithomelabs.CFTunnels.Models.Config; import com.hithomelabs.CFTunnels.Models.Groups; import com.hithomelabs.CFTunnels.Models.TunnelResponse; import com.hithomelabs.CFTunnels.Services.CloudflareAPIService; +import com.hithomelabs.CFTunnels.Services.MappingRequestService; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -66,6 +67,9 @@ class TunnelControllerTest { @MockitoBean RestTemplateConfig restTemplateConfig; + @MockitoBean + MappingRequestService mappingRequestService; + private static final String tunnelResponseSmallIngressFile = "tunnelResponseSmallIngress.json"; private static final String tunnelResponseLargeIngressFile = "tunnelResponseLargeIngress.json"; -- 2.45.2 From cfe40735e6a57d9a2649860b42bc2daed3bc9fc0 Mon Sep 17 00:00:00 2001 From: hitanshu310 Date: Wed, 14 Jan 2026 23:24:39 +0530 Subject: [PATCH 2/4] Hithomelabs/HomeLabDocker#33 making ci and integration tests initialize Embedded H2 database, fixing integration test --- build.gradle | 2 +- src/main/resources/application-ci.properties | 7 +++++++ src/main/resources/application-integration.properties | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application-ci.properties diff --git a/build.gradle b/build.gradle index 90dc143..1034cb7 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ java { } test { - systemProperty 'spring.profiles.active', 'test' + systemProperty 'spring.profiles.active', 'ci' useJUnitPlatform { excludeTags 'integration' } diff --git a/src/main/resources/application-ci.properties b/src/main/resources/application-ci.properties new file mode 100644 index 0000000..9d7d1f0 --- /dev/null +++ b/src/main/resources/application-ci.properties @@ -0,0 +1,7 @@ +api.baseUrl=https://testcf.hithomelabs.com + +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.hibernate.ddl-auto=none \ No newline at end of file diff --git a/src/main/resources/application-integration.properties b/src/main/resources/application-integration.properties index 055765b..7fd1b35 100644 --- a/src/main/resources/application-integration.properties +++ b/src/main/resources/application-integration.properties @@ -1,3 +1,9 @@ cloudflare.accountId=${CLOUDFLARE_ACCOUNT_ID} cloudflare.apiKey=${CLOUDFLARE_API_KEY} cloudflare.email=${CLOUDFLARE_EMAIL} + +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.hibernate.ddl-auto=none \ No newline at end of file -- 2.45.2 From c8a25cf4382ba403f47fe3f820aec694340644db Mon Sep 17 00:00:00 2001 From: hitanshu310 Date: Fri, 23 Jan 2026 02:11:32 +0530 Subject: [PATCH 3/4] Configure springdoc swagger oauth client-id from environment variable - Update application.properties to use SWAGGER_OAUTH_CLIENT_ID env var - Add SWAGGER_OAUTH_CLIENT_ID to docker-compose.yaml environment - Add SWAGGER_OAUTH_CLIENT_ID to IntelliJ run configuration --- docker-compose.yaml | 1 + src/main/resources/application.properties | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/docker-compose.yaml b/docker-compose.yaml index 9eb1198..1983e88 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -14,6 +14,7 @@ services: - HOST_PORT=${HOST_PORT} - POSTGRES_USER=${POSTGRES_USERNAME} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - SWAGGER_OAUTH_CLIENT_ID=${SWAGGER_OAUTH_CLIENT_ID} env_file: - stack.env restart: unless-stopped diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a0264d2..283d942 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -18,6 +18,13 @@ spring.security.oauth2.client.provider.cftunnels.user-info-uri=https://auth.hith spring.security.oauth2.client.provider.cftunnels.jwk-set-uri=https://auth.hithomelabs.com/application/o/cftunnels/jwks/ spring.security.oauth2.client.provider.cftunnels.issuer-uri=https://auth.hithomelabs.com/application/o/cftunnels/ +springdoc.swagger-ui.oauth.client-id=${SWAGGER_OAUTH_CLIENT_ID} +springdoc.swagger-ui.oauth.client-secret= # leave empty for public client +springdoc.swagger-ui.oauth.use-pkce=true +springdoc.swagger-ui.oauth.scopes=openid,profile,email +springdoc.swagger-ui.oauth.authorization-url=https://auth.hithomelabs.com/application/o/authorize/ +springdoc.swagger-ui.oauth.token-url=https://auth.hithomelabs.com/application/o/token/ + spring.datasource.url=jdbc:postgresql://192.168.0.100:5432/cftunnel spring.datasource.username=${POSTGRES_USERNAME} spring.datasource.password=${POSTGRES_PASSWORD} -- 2.45.2 From d2d8e74ba9292959677755fe2c11267d52be75ab Mon Sep 17 00:00:00 2001 From: hitanshu310 Date: Fri, 23 Jan 2026 02:16:45 +0530 Subject: [PATCH 4/4] Add OAuth2 security configuration to Swagger UI and clean up unused redirects - Configure OpenAPI with OAuth2 authorization code flow and required scopes - Add security scheme and requirements for API documentation - Remove unused swagger redirect methods from HomeController - Comment out swagger endpoint permissions in SecurityConfig --- .../CFTunnels/Config/OpenApiConfig.java | 28 ++++++++++++++++++- .../Config/Security/SecuirtyConfig.java | 1 + .../CFTunnels/Controllers/HomeController.java | 18 +----------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/hithomelabs/CFTunnels/Config/OpenApiConfig.java b/src/main/java/com/hithomelabs/CFTunnels/Config/OpenApiConfig.java index 1f2af4a..72639fe 100644 --- a/src/main/java/com/hithomelabs/CFTunnels/Config/OpenApiConfig.java +++ b/src/main/java/com/hithomelabs/CFTunnels/Config/OpenApiConfig.java @@ -1,6 +1,8 @@ package com.hithomelabs.CFTunnels.Config; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.security.*; import io.swagger.v3.oas.models.servers.Server; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -16,13 +18,37 @@ public class OpenApiConfig { @Value("${api.baseUrl}") private String baseUrl; + @Value("${springdoc.swagger-ui.oauth.authorization-url}") + private String authorizationUri; + + @Value("${springdoc.swagger-ui.oauth.token-url}") + private String tokenUri; + @Bean - public OpenAPI openAPI(){ + public OpenAPI openAPI() { Server httpsServer = new Server().url(baseUrl); OpenAPI openApi = new OpenAPI(); ArrayList servers = new ArrayList<>(); servers.add(httpsServer); openApi.setServers(servers); + openApi.addSecurityItem(new SecurityRequirement().addList("oidcAuth")) + .components(new Components() + .addSecuritySchemes("oidcAuth", + new SecurityScheme() + .type(SecurityScheme.Type.OAUTH2) + .flows(new OAuthFlows() + .authorizationCode(new OAuthFlow() + .authorizationUrl(authorizationUri) + .tokenUrl(tokenUri) + .scopes(new Scopes() + .addString("openid", "OpenID scope") + .addString("profile", "OpenID profile") + .addString("email", "OpenID email")) + ) + ) + ) + ) + .addSecurityItem(new SecurityRequirement().addList("oidcAuth")); return openApi; } } diff --git a/src/main/java/com/hithomelabs/CFTunnels/Config/Security/SecuirtyConfig.java b/src/main/java/com/hithomelabs/CFTunnels/Config/Security/SecuirtyConfig.java index 81def11..5cd6646 100644 --- a/src/main/java/com/hithomelabs/CFTunnels/Config/Security/SecuirtyConfig.java +++ b/src/main/java/com/hithomelabs/CFTunnels/Config/Security/SecuirtyConfig.java @@ -28,6 +28,7 @@ public class SecuirtyConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth + //.requestMatchers( "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html" ).permitAll() .anyRequest().authenticated() ).csrf(csrf -> csrf.disable()) .with(new OAuth2LoginConfigurer<>(), diff --git a/src/main/java/com/hithomelabs/CFTunnels/Controllers/HomeController.java b/src/main/java/com/hithomelabs/CFTunnels/Controllers/HomeController.java index 43ea57a..87bffcf 100644 --- a/src/main/java/com/hithomelabs/CFTunnels/Controllers/HomeController.java +++ b/src/main/java/com/hithomelabs/CFTunnels/Controllers/HomeController.java @@ -11,22 +11,6 @@ public class HomeController implements ErrorController { private static final String ERROR_PATH = "/error"; - /** - * Redirects the root (including any query params like ?continue=…) - * straight into Swagger UI. - */ - @GetMapping("/") - public String rootRedirect() { - return "redirect:/swagger-ui/index.html"; - } - - /** - * Catches any errors (404s, unhandled paths) and punts them - * into the same Swagger UI page. - */ - @RequestMapping(ERROR_PATH) - public String onError() { - return "redirect:/swagger-ui/index.html"; - } + } -- 2.45.2