package net.gepafin.tendermanagement.config; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; 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; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.HubEntity; import net.gepafin.tendermanagement.entities.SamlResponseEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.SamlResponseStatusEnum; import net.gepafin.tendermanagement.repositories.SamlResponseRepository; import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; @Component public class SamlSuccessHandler implements AuthenticationSuccessHandler { private final Logger logger = LoggerFactory.getLogger(SamlSuccessHandler.class); @Autowired private SamlResponseRepository samlResponseLogRepository; @Autowired private UserRepository userRepository; @Value("${fe.base.url}") private String feBaseUrl; @Autowired private HubService hubService; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { try { logger.info("SAML login in Authentication Success Handler"); Saml2Authentication samlAuth = (Saml2Authentication) authentication; Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) samlAuth.getPrincipal(); Map> userAttributes = principal.getAttributes(); String token = Utils.generateSecureToken(); logger.info("SAML User Attributes: " + userAttributes); // Extracting raw SAML response String samlResponse = samlAuth.getSaml2Response(); logger.info("Raw SAML Response: " + samlResponse); // If samlResponse is already in XML format, do not Base64 decode it DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new ByteArrayInputStream(samlResponse.getBytes())); // Remove the Base64 decoding // 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); SamlResponseEntity samlResponseLogEntity = samlResponseLogRepository .findByInResponseToAndStatus(inResponseTo, SamlResponseStatusEnum.INITIATED.getValue()) .orElseThrow(() -> new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.INVALID_REQUEST))); ObjectMapper objectMapper = new ObjectMapper(); String userAttributesJson = objectMapper.writeValueAsString(userAttributes); samlResponseLogEntity.setAuthenticationObject(userAttributesJson); samlResponseLogEntity.setToken(token); samlResponseLogEntity.setStatus(SamlResponseStatusEnum.SUCCESS.getValue()); samlResponseLogEntity.setInResponseTo(inResponseTo); samlResponseLogEntity.setSamlId(responseId); samlResponseLogEntity.setIssueInstant(issueInstant); samlResponseLogRepository.save(samlResponseLogEntity); HubEntity hub = hubService.getHubByUuid(samlResponseLogEntity.getHubUuid()); String redirectUrl = feBaseUrl; if (Boolean.FALSE.equals(StringUtils.isEmpty(hub.getDomainName()))) { redirectUrl = hub.getDomainName(); } logger.info("SAML login successful for user: " + principal.getName()); String cf = userAttributes.get("CodiceFiscale").get(0).toString(); UserEntity userEntity = userRepository.findByBeneficiaryCodiceFiscaleAndHubId(cf, hub.getId()).orElse(null); if (userEntity == null) { redirectUrl += "/registration?temp_token=" + token; } else { redirectUrl += "/login?temp_token=" + token; } response.sendRedirect(redirectUrl); logger.info("SAML redirect Url: " + redirectUrl); } catch (Exception e) { logger.error("Error processing SAML success handler", e); } } public void validateToken(String token, String codiceFiscale, String hubUuid) { SamlResponseEntity samlResponseLogEntity = samlResponseLogRepository.findByToken(token); if (samlResponseLogEntity == null || Boolean.FALSE.equals(hubUuid.equals(samlResponseLogEntity.getHubUuid()))) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_TOKEN_MSG)); } Map> userAttributes = Utils .convertStringIntoMap(samlResponseLogEntity.getAuthenticationObject()); String cf = userAttributes.get("CodiceFiscale").get(0).toString(); if (codiceFiscale == null || Boolean.FALSE.equals(codiceFiscale.equals(cf))) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_TOKEN_MSG)); } } }