mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-10-25 11:17:28 +02:00 
			
		
		
		
	contextPath fixes
This commit is contained in:
		
							parent
							
								
									3911be0177
								
							
						
					
					
						commit
						8acab77ae3
					
				| @ -5,11 +5,13 @@ import java.io.IOException; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.core.Authentication; | ||||
| import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; | ||||
| import org.springframework.security.web.savedrequest.SavedRequest; | ||||
| import org.springframework.stereotype.Component; | ||||
| 
 | ||||
| import jakarta.servlet.ServletException; | ||||
| import jakarta.servlet.http.HttpServletRequest; | ||||
| import jakarta.servlet.http.HttpServletResponse; | ||||
| import jakarta.servlet.http.HttpSession; | ||||
| 
 | ||||
| @Component | ||||
| public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { | ||||
| @ -19,8 +21,32 @@ public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthent | ||||
| 
 | ||||
|     @Override | ||||
|     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { | ||||
|         String username = request.getParameter("username"); | ||||
|     	String username = request.getParameter("username"); | ||||
|         loginAttemptService.loginSucceeded(username); | ||||
|         super.onAuthenticationSuccess(request, response, authentication); | ||||
|          | ||||
|          | ||||
|         // Get the saved request | ||||
|         HttpSession session = request.getSession(false); | ||||
|         SavedRequest savedRequest = session != null ? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST") : null; | ||||
|         if (savedRequest != null && !isStaticResource(savedRequest)) { | ||||
|             // Redirect to the original destination | ||||
|             super.onAuthenticationSuccess(request, response, authentication); | ||||
|         } else { | ||||
|             // Redirect to the root URL (considering context path) | ||||
|             getRedirectStrategy().sendRedirect(request, response, "/"); | ||||
|         } | ||||
|          | ||||
|         //super.onAuthenticationSuccess(request, response, authentication); | ||||
|     } | ||||
|      | ||||
|     private boolean isStaticResource(SavedRequest savedRequest) { | ||||
|         String requestURI = savedRequest.getRedirectUrl(); | ||||
|         return requestURI.startsWith("/css/")  | ||||
|         		|| requestURI.startsWith("/js/") | ||||
|         		|| requestURI.startsWith("/images/") | ||||
|         		|| requestURI.startsWith("/public/") | ||||
|         		|| requestURI.startsWith("/pdfjs/") | ||||
|         		|| requestURI.endsWith(".svg"); | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | ||||
| @ -7,6 +7,7 @@ import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.security.authentication.dao.DaoAuthenticationProvider; | ||||
| import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; | ||||
| import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; | ||||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||||
| import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||||
| import org.springframework.security.core.userdetails.UserDetailsService; | ||||
| @ -15,12 +16,13 @@ import org.springframework.security.crypto.password.PasswordEncoder; | ||||
| import org.springframework.security.web.SecurityFilterChain; | ||||
| import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | ||||
| import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; | ||||
| import org.springframework.security.web.savedrequest.NullRequestCache; | ||||
| import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | ||||
| 
 | ||||
| import stirling.software.SPDF.repository.JPATokenRepositoryImpl; | ||||
| @Configuration | ||||
| @EnableWebSecurity() | ||||
| @EnableGlobalMethodSecurity(prePostEnabled = true) | ||||
| @EnableMethodSecurity | ||||
| public class SecurityConfiguration { | ||||
| 
 | ||||
|     @Autowired | ||||
| @ -41,9 +43,7 @@ public class SecurityConfiguration { | ||||
|     @Autowired | ||||
|     private UserAuthenticationFilter userAuthenticationFilter; | ||||
| 
 | ||||
|     @Autowired | ||||
|     private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler; | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
|     @Autowired | ||||
|     private  LoginAttemptService loginAttemptService; | ||||
| @ -63,11 +63,13 @@ public class SecurityConfiguration { | ||||
| 	        http | ||||
| 	            .formLogin(formLogin -> formLogin | ||||
| 	                .loginPage("/login") | ||||
| 	                .successHandler(customAuthenticationSuccessHandler) | ||||
| 	               // .defaultSuccessUrl("/") | ||||
| 	                .successHandler(new CustomAuthenticationSuccessHandler()) | ||||
| 	                .defaultSuccessUrl("/") | ||||
| 	                .failureHandler(new CustomAuthenticationFailureHandler(loginAttemptService)) | ||||
| 	                .permitAll() | ||||
| 	            ) | ||||
| 	            ).requestCache(requestCache -> requestCache | ||||
| 	                    .requestCache(new NullRequestCache()) | ||||
| 	            	    ) | ||||
| 	            .logout(logout -> logout | ||||
| 	            		.logoutRequestMatcher(new AntPathRequestMatcher("/logout")) | ||||
| 	                    .logoutSuccessUrl("/login?logout=true") | ||||
| @ -79,8 +81,19 @@ public class SecurityConfiguration { | ||||
|                     .tokenValiditySeconds(1209600) // 2 weeks | ||||
|                 ) | ||||
| 	            .authorizeHttpRequests(authz -> authz | ||||
| 	                    .requestMatchers(req -> req.getRequestURI().startsWith("/login") || req.getRequestURI().endsWith(".svg") || req.getRequestURI().startsWith("/register") || req.getRequestURI().startsWith("/error") || req.getRequestURI().startsWith("/images/") ||  req.getRequestURI().startsWith("/public/") || req.getRequestURI().startsWith("/css/") || req.getRequestURI().startsWith("/js/")) | ||||
| 	                    .permitAll() | ||||
| 	                    .requestMatchers(req ->  { | ||||
| 	                        String uri = req.getRequestURI(); | ||||
| 	                        String contextPath = req.getContextPath(); | ||||
| 
 | ||||
| 	                        // Remove the context path from the URI | ||||
| 	                        String trimmedUri = uri.startsWith(contextPath) ? uri.substring(contextPath.length()) : uri; | ||||
| 
 | ||||
| 	                        return trimmedUri.startsWith("/login") || trimmedUri.endsWith(".svg") ||  | ||||
| 	                               trimmedUri.startsWith("/register") || trimmedUri.startsWith("/error") ||  | ||||
| 	                               trimmedUri.startsWith("/images/") || trimmedUri.startsWith("/public/") ||  | ||||
| 	                               trimmedUri.startsWith("/css/") || trimmedUri.startsWith("/js/"); | ||||
| 	                    } | ||||
| 	                    ).permitAll() | ||||
| 	                    .anyRequest().authenticated() | ||||
| 	                ) | ||||
| 	            .userDetailsService(userDetailsService) | ||||
|  | ||||
| @ -74,8 +74,10 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { | ||||
|         // If we still don't have any authentication, deny the request | ||||
|         if (authentication == null || !authentication.isAuthenticated()) { | ||||
|         	String method = request.getMethod(); | ||||
|         	if ("GET".equalsIgnoreCase(method) && !"/login".equals(requestURI)) { | ||||
|         		 response.sendRedirect("/login");  // redirect to the login page | ||||
|         	String contextPath = request.getContextPath(); | ||||
|         	 | ||||
|         	if ("GET".equalsIgnoreCase(method) && !  (contextPath + "/login").equals(requestURI)) { | ||||
|         		 response.sendRedirect(contextPath + "/login");  // redirect to the login page | ||||
|         	     return; | ||||
|             } else { | ||||
| 	            response.setStatus(HttpStatus.UNAUTHORIZED.value()); | ||||
| @ -90,15 +92,17 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { | ||||
|     @Override | ||||
|     protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { | ||||
|         String uri = request.getRequestURI(); | ||||
| 
 | ||||
|         String contextPath = request.getContextPath(); | ||||
|         String[] permitAllPatterns = { | ||||
|             "/login", | ||||
|             "/register", | ||||
|             "/error", | ||||
|             "/images/", | ||||
|             "/public/", | ||||
|             "/css/", | ||||
|             "/js/" | ||||
|         		contextPath + "/login", | ||||
|         		contextPath + "/register", | ||||
|         		contextPath + "/error", | ||||
|         		contextPath + "/images/", | ||||
|         		contextPath + "/public/", | ||||
|         		contextPath + "/css/", | ||||
|         		contextPath + "/js/", | ||||
|         		contextPath +  "/pdfjs/", | ||||
|         		contextPath +  "/site.webmanifest" | ||||
|         }; | ||||
| 
 | ||||
|         for (String pattern : permitAllPatterns) { | ||||
|  | ||||
| @ -15,14 +15,22 @@ import org.springframework.web.client.RestTemplate; | ||||
| import com.fasterxml.jackson.databind.JsonNode; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| 
 | ||||
| import jakarta.servlet.ServletContext; | ||||
| import stirling.software.SPDF.model.ApiEndpoint; | ||||
| import stirling.software.SPDF.model.Role; | ||||
| @Service | ||||
| public class ApiDocService { | ||||
| 
 | ||||
|     private final Map<String, ApiEndpoint> apiDocumentation = new HashMap<>(); | ||||
|     private final String apiDocsUrl = "http://localhost:8080/v1/api-docs"; // URL to your API documentation | ||||
| 
 | ||||
|     @Autowired | ||||
|     private ServletContext servletContext; | ||||
| 
 | ||||
|     private String getApiDocsUrl() { | ||||
|         String contextPath = servletContext.getContextPath(); | ||||
|         return "http://localhost:8080" + contextPath + "/v1/api-docs"; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     @Autowired(required=false) | ||||
| 	private UserServiceInterface userService; | ||||
| @ -44,7 +52,7 @@ public class ApiDocService { | ||||
|             HttpEntity<String> entity = new HttpEntity<>(headers); | ||||
| 
 | ||||
|             RestTemplate restTemplate = new RestTemplate(); | ||||
|             ResponseEntity<String> response = restTemplate.exchange(apiDocsUrl, HttpMethod.GET, entity, String.class); | ||||
|             ResponseEntity<String> response = restTemplate.exchange(getApiDocsUrl(), HttpMethod.GET, entity, String.class); | ||||
|             String apiDocsJson = response.getBody(); | ||||
| 
 | ||||
|             ObjectMapper mapper = new ObjectMapper(); | ||||
|  | ||||
| @ -50,6 +50,7 @@ import com.fasterxml.jackson.databind.JsonNode; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| 
 | ||||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| import jakarta.servlet.ServletContext; | ||||
| import stirling.software.SPDF.model.ApplicationProperties; | ||||
| import stirling.software.SPDF.model.PipelineConfig; | ||||
| import stirling.software.SPDF.model.PipelineOperation; | ||||
| @ -117,6 +118,14 @@ public class PipelineController { | ||||
| 		return userService.getApiKeyForUser(Role.INTERNAL_API_USER.getRoleId()); | ||||
| 	} | ||||
| 	 | ||||
| 	 @Autowired | ||||
| 	    private ServletContext servletContext; | ||||
| 
 | ||||
| 	    private String getBaseUrl() { | ||||
| 	        String contextPath = servletContext.getContextPath(); | ||||
| 	        return "http://localhost:8080" + contextPath + "/"; | ||||
| 	    } | ||||
| 	     | ||||
| 	private void handleDirectory(Path dir) throws Exception { | ||||
| 		logger.info("Handling directory: {}", dir); | ||||
| 
 | ||||
| @ -337,7 +346,7 @@ public class PipelineController { | ||||
| 					HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers); | ||||
| 
 | ||||
| 					RestTemplate restTemplate = new RestTemplate(); | ||||
| 					String url = "http://localhost:8080/" + operation; | ||||
| 					String url = getBaseUrl() + operation; | ||||
| 
 | ||||
| 					ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class); | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #searchBar { | ||||
| 	background-image: url('/images/search.svg'); | ||||
| 	background-image: url('../images/search.svg'); | ||||
| 	background-position: 16px 16px; | ||||
| 	background-repeat: no-repeat; | ||||
| 	width: 100%; | ||||
|  | ||||
| @ -130,7 +130,7 @@ document.getElementById('submitConfigBtn').addEventListener('click', function() | ||||
| 	formData.append('json', pipelineConfigJson); | ||||
| 	console.log("formData", formData); | ||||
| 
 | ||||
| 	fetch('/api/v1/pipeline/handleData', { | ||||
| 	fetch('api/v1/pipeline/handleData', { | ||||
|     method: 'POST', | ||||
|     body: formData | ||||
| 	}) | ||||
|  | ||||
| @ -306,7 +306,7 @@ | ||||
|                          | ||||
|                          | ||||
|                         <div class="mb-3 mt-4"> | ||||
|                             <a href="/logout"> | ||||
|                             <a href="logout"> | ||||
|                                 <button type="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</button> | ||||
|                             </a> | ||||
|                             <a th:if="${role == 'ROLE_ADMIN'}" href="addUsers" target="_blank"> | ||||
|  | ||||
| @ -293,7 +293,7 @@ | ||||
|                     </a> | ||||
|                 </div> | ||||
|                 <div class="modal-footer"> | ||||
|                     <a th:if="${@loginEnabled}" href="/logout"> | ||||
|                     <a th:if="${@loginEnabled}" href="logout"> | ||||
|                         <button type="button" class="btn btn-danger" th:text="#{settings.signOut}">Sign Out</button> | ||||
|                     </a> | ||||
|                     <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user