From 07498ce1ef3507d6cacf48ffa30072656c1e2a19 Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 17 Oct 2024 19:39:25 -0700 Subject: [PATCH] Updated SAML config --- .../tendermanagement/config/SamlConfig.java | 46 +++++++++++-------- .../config/SamlRequestFilter.java | 24 ++++++++++ .../config/SamlSuccessHandler.java | 28 +++++++++++ .../config/SecurityConfig.java | 31 ++++++------- 4 files changed, 94 insertions(+), 35 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/config/SamlRequestFilter.java diff --git a/src/main/java/net/gepafin/tendermanagement/config/SamlConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SamlConfig.java index c66e26f1..050c4167 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SamlConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SamlConfig.java @@ -41,6 +41,10 @@ import org.springframework.security.saml2.provider.service.web.DefaultRelyingPar import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import jakarta.servlet.http.HttpServletRequest; @Configuration public class SamlConfig { @@ -123,28 +127,34 @@ public class SamlConfig { return authnRequest; } -@Bean -public Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) { - RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations); - OpenSaml4AuthenticationRequestResolver authenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(registrationResolver); + @Bean + public Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) { + RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations); + OpenSaml4AuthenticationRequestResolver authenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(registrationResolver); - authenticationRequestResolver.setAuthnRequestCustomizer((context) -> { - // Set the required attributes - AuthnRequest authnRequest = context.getAuthnRequest(); - authnRequest.setID("_" + UUID.randomUUID().toString()); // Add a unique ID - authnRequest.setVersion(SAMLVersion.VERSION_20); // Ensure version is 2.0 - authnRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); // HTTP-POST + authenticationRequestResolver.setAuthnRequestCustomizer((context) -> { - // Set Authentication Context - authnRequest.setRequestedAuthnContext(buildRequestedAuthnContext()); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + String hubId = (String) request.getAttribute("hubId"); - // Log the SAML AuthnRequest after setting context - String samlRequest = SamlRequestLogger.convertSAMLObjectToString(authnRequest); - logger.info("SAML AuthnRequest after setting context: " + samlRequest); - }); + logger.info("Hub id " + hubId); + + // Continue with normal AuthnRequest configuration + AuthnRequest authnRequest = context.getAuthnRequest(); + authnRequest.setID("_" + UUID.randomUUID().toString()+":"+hubId); + authnRequest.setVersion(SAMLVersion.VERSION_20); + authnRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); + authnRequest.setRequestedAuthnContext(buildRequestedAuthnContext()); + + + // Log the SAML AuthnRequest after setting context + String samlRequest = SamlRequestLogger.convertSAMLObjectToString(authnRequest); + logger.info("SAML AuthnRequest after setting context: " + samlRequest); + }); + + return authenticationRequestResolver; + } - return authenticationRequestResolver; -} private RequestedAuthnContext buildRequestedAuthnContext() { AuthnContextClassRefBuilder authnContextClassRefBuilder = new AuthnContextClassRefBuilder(); diff --git a/src/main/java/net/gepafin/tendermanagement/config/SamlRequestFilter.java b/src/main/java/net/gepafin/tendermanagement/config/SamlRequestFilter.java new file mode 100644 index 00000000..a7b3a664 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/config/SamlRequestFilter.java @@ -0,0 +1,24 @@ +package net.gepafin.tendermanagement.config; + +import java.io.IOException; + +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class SamlRequestFilter extends OncePerRequestFilter { + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + String hub = request.getParameter("hubId"); + if (hub != null) { + request.setAttribute("hubId", hub); // Store the hub ID as an attribute + } + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/config/SamlSuccessHandler.java b/src/main/java/net/gepafin/tendermanagement/config/SamlSuccessHandler.java index 868b0eae..c58318a2 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SamlSuccessHandler.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SamlSuccessHandler.java @@ -1,9 +1,14 @@ package net.gepafin.tendermanagement.config; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.Base64; import java.util.List; import java.util.Map; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -13,6 +18,8 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2A import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import com.fasterxml.jackson.databind.ObjectMapper; @@ -62,6 +69,27 @@ public class SamlSuccessHandler implements AuthenticationSuccessHandler { samlResponseLogEntity.setToken(token); samlResponseLogRepository.save(samlResponseLogEntity); + + // Extracting raw SAML response + String samlResponse = samlAuth.getSaml2Response(); + logger.info("Raw SAML Response: " + samlResponse); + + // Parsing the SAML response as XML + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(new ByteArrayInputStream(Base64.getDecoder().decode(samlResponse))); + + // Extracting ID, InResponseTo, and IssueInstant from the Response element + Element responseElement = (Element) document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:protocol", "Response").item(0); + String responseId = responseElement.getAttribute("ID"); + String inResponseTo = responseElement.getAttribute("InResponseTo"); + String issueInstant = responseElement.getAttribute("IssueInstant"); + + logger.info("SAML Response ID: " + responseId); + logger.info("InResponseTo: " + inResponseTo); + logger.info("IssueInstant: " + issueInstant); + String redirectUrl = feBaseUrl; logger.info("SAML login successful for user: " + principal.getName()); diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java index 89182902..090f3688 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java @@ -15,6 +15,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; @@ -109,23 +110,19 @@ public class SecurityConfig { .requestMatchers("/v1/user/reset-password/initiate").permitAll() .requestMatchers("/v1/user/reset-password").permitAll() .anyRequest().authenticated()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) - .exceptionHandling(exceptionHandling -> exceptionHandling - .authenticationEntryPoint((request, response, authException) -> { - // Send 403 Forbidden when there is no JWT token provided - response.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden: Authentication token is missing or invalid"); - }) - ) - .addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class) - .addFilterBefore(new JWTFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class) - // Add SAML2 login configuration (for BENEFICIARI) - /* - * .saml2Login(saml -> saml.loginPage("/saml/login") // Entry point for SAML - * login .defaultSuccessUrl("/") // Redirect after successful SAML login ); - */ - .saml2Login(saml -> saml.defaultSuccessUrl("/").successHandler(samlSuccessHandler) - .failureHandler(samlFailureHandler)); - + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) + .exceptionHandling(exceptionHandling -> exceptionHandling + .authenticationEntryPoint((request, response, authException) -> { + // Send 403 Forbidden when there is no JWT token provided + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden: Authentication token is missing or invalid"); + }) + ) + .addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(new JWTFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(new SamlRequestFilter(), Saml2WebSsoAuthenticationRequestFilter.class) // Add the custom SAML filter + .saml2Login(saml -> saml.defaultSuccessUrl("/") + .successHandler(samlSuccessHandler) + .failureHandler(samlFailureHandler)); return http.build(); }