From 470081b60f516f647e0c416e24f9403a15d9a8b2 Mon Sep 17 00:00:00 2001 From: razakpm Date: Tue, 18 Jun 2024 18:25:21 +0530 Subject: [PATCH 1/2] feat: disable login requirements in local environment #15 --- .envrc.example | 6 +- hub-prime/pom.xml | 4 +- .../service/http/NoAuthSecurityConfig.java | 47 +++++++++++++++ .../techbd/service/http/SecurityConfig.java | 49 ++++++++++++++- .../service/http/hub/prime/Controller.java | 4 +- .../resources/templates/layout/prime.html | 59 ++++++++++++------- 6 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 hub-prime/src/main/java/org/techbd/service/http/NoAuthSecurityConfig.java diff --git a/.envrc.example b/.envrc.example index 19d35ba6513..c0b884bb730 100644 --- a/.envrc.example +++ b/.envrc.example @@ -4,7 +4,11 @@ # If you want use these, remember to start VSCode or your IDE after `direnv allow` -# use `sandbox` (localhost), `devl`, `stage`, `prod` + +# use Spring profiles as 'localopen' for testing locally with no authentication, `sandbox` for testing with auth in localhost , `devl`, `stage`, `prod` +export SPRING_PROFILES_ACTIVE=sandbox + +# use `localopen', `sandbox` (localhost), `devl`, `stage`, `prod` export SPRING_PROFILES_ACTIVE=sandbox export sandbox_TECHBD_UDI_DS_PRIME_JDBC_URL=jdbc:postgresql://aws.neon.tech/persistence-prime export sandbox_TECHBD_UDI_DS_PRIME_JDBC_USERNAME=persistence-prime diff --git a/hub-prime/pom.xml b/hub-prime/pom.xml index 900ae361dc9..725d1de8176 100644 --- a/hub-prime/pom.xml +++ b/hub-prime/pom.xml @@ -205,11 +205,11 @@ jaxb-impl 4.0.5 - + com.google.code.gson gson diff --git a/hub-prime/src/main/java/org/techbd/service/http/NoAuthSecurityConfig.java b/hub-prime/src/main/java/org/techbd/service/http/NoAuthSecurityConfig.java new file mode 100644 index 00000000000..49b86ad1700 --- /dev/null +++ b/hub-prime/src/main/java/org/techbd/service/http/NoAuthSecurityConfig.java @@ -0,0 +1,47 @@ +package org.techbd.service.http; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.filter.ForwardedHeaderFilter; + +@Configuration +@EnableWebSecurity +@ConfigurationProperties(prefix = "spring.security.oauth2.client.registration.github") +@Profile("localopen") +public class NoAuthSecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeRequests(authorizeRequests -> authorizeRequests + .anyRequest().permitAll()) + .csrf().disable(); // Disable CSRF for simplicity in sandbox + + return http.build(); + } + + @Bean + public CorsFilter corsFilter() { + // primarily setup for Swagger UI and OpenAPI integration + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.addAllowedOriginPattern("*"); // Customize as needed + config.addAllowedMethod("*"); + config.addAllowedHeader("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + @Bean + ForwardedHeaderFilter forwardedHeaderFilter() { + return new ForwardedHeaderFilter(); + } +} diff --git a/hub-prime/src/main/java/org/techbd/service/http/SecurityConfig.java b/hub-prime/src/main/java/org/techbd/service/http/SecurityConfig.java index f7cd3776b07..1eac4a2606c 100644 --- a/hub-prime/src/main/java/org/techbd/service/http/SecurityConfig.java +++ b/hub-prime/src/main/java/org/techbd/service/http/SecurityConfig.java @@ -1,6 +1,9 @@ package org.techbd.service.http; import org.springframework.context.annotation.Bean; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; @@ -9,12 +12,20 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.filter.ForwardedHeaderFilter; +import org.springframework.web.filter.OncePerRequestFilter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.techbd.service.http.filter.GitHubUserAuthorizationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @ConfigurationProperties(prefix = "spring.security.oauth2.client.registration.github") +@Profile("!localopen") public class SecurityConfig { @Bean @@ -22,16 +33,18 @@ public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws E // allow authentication for security // and turn off CSRF to allow POST methods http.authorizeHttpRequests(authorize -> authorize - .requestMatchers("/login/**", "/oauth2/**", "/", "/Bundle/**", "/metadata", + .requestMatchers("/login/**", "/oauth2/**", "/", "/Bundle", "/Bundle/**", "/metadata", "/docs/api/interactive/swagger-ui/**", "/docs/api/interactive/**", "/docs/api/openapi/**") .permitAll() .anyRequest().authenticated()) .oauth2Login(oauth2Login -> oauth2Login .defaultSuccessUrl("/home", true)) .csrf(AbstractHttpConfigurer::disable) - .addFilterAfter(new GitHubUserAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class); + .addFilterAfter(new GitHubUserAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(new ExceptionHandlingFilter(), GitHubUserAuthorizationFilter.class); // allow us to show our own content in IFRAMEs (e.g. Swagger, etc.) http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin())); + // System.out.println(http.); return http.build(); } @@ -52,4 +65,36 @@ ForwardedHeaderFilter forwardedHeaderFilter() { return new ForwardedHeaderFilter(); } + public class ExceptionHandlingFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, + @NotNull FilterChain filterChain) + throws ServletException, IOException { + + if (request.getRequestURI().startsWith("/Bundle")) { + + // Check if X-TechBD-Tenant-ID header is missing + if (request.getHeader("X-TechBD-Tenant-ID") == null) { + handleError(response, HttpServletResponse.SC_NOT_FOUND, "X-TechBD-Tenant-ID header is missing"); + return; + } + + // Check if Content-Type is application/json + if (!"application/json".equals(request.getContentType())) { + handleError(response, HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, + "Content-Type must be application/json"); + return; + } + + } + filterChain.doFilter(request, response); + } + + private void handleError(HttpServletResponse response, int statusCode, String message) throws IOException { + response.setStatus(statusCode); + response.getWriter().write(message); + } + } + } diff --git a/hub-prime/src/main/java/org/techbd/service/http/hub/prime/Controller.java b/hub-prime/src/main/java/org/techbd/service/http/hub/prime/Controller.java index a12535895f1..6bd1f73b81e 100644 --- a/hub-prime/src/main/java/org/techbd/service/http/hub/prime/Controller.java +++ b/hub-prime/src/main/java/org/techbd/service/http/hub/prime/Controller.java @@ -217,7 +217,7 @@ public String metadata(final Model model, HttpServletRequest request) { return "metadata.xml"; } - @PostMapping(value = { "/Bundle/" }, consumes = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = { "/Bundle" }, consumes = MediaType.APPLICATION_JSON_VALUE) @ResponseBody @Async public Object validateBundleAndCreate(final @RequestBody @Nonnull String payload, @@ -486,7 +486,7 @@ public List observeRecentSftpInteractions() { @Operation(summary = "Recent HTTP Request/Response Interactions") @GetMapping("/admin/observe/interaction/https/recent.json") @ResponseBody - public Page observeRecentHttpsInteractions(final Model model, + public Page observeRecentHttpsInteractions(final Model model, final HttpServletRequest request, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { diff --git a/hub-prime/src/main/resources/templates/layout/prime.html b/hub-prime/src/main/resources/templates/layout/prime.html index 54e96ef42b8..635dfcd522c 100644 --- a/hub-prime/src/main/resources/templates/layout/prime.html +++ b/hub-prime/src/main/resources/templates/layout/prime.html @@ -131,28 +131,43 @@ id="user-menu-button" aria-expanded="false" aria-haspopup="true"> Open user menu - - -
- - User Profile - -