diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java index e530b479..c83cc513 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java @@ -11,8 +11,11 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.PKCS8EncodedKeySpec; import java.time.Instant; +import java.util.List; +import java.util.Map; import java.util.UUID; +import org.apache.xml.security.Init; import org.bouncycastle.util.io.pem.PemReader; import org.opensaml.core.config.InitializationService; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; @@ -47,6 +50,8 @@ 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.core.Saml2X509Credential; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; @@ -65,7 +70,7 @@ import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.xml.security.Init; + import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.security.SecurityRequirement; @@ -184,70 +189,54 @@ public class SecurityConfig { .saml2Login(saml -> saml.defaultSuccessUrl("/") .successHandler((request, response, authentication) -> { - logger.error("SAML success login"); - SamlResponseLogEntity samlResponseLogEntity = new SamlResponseLogEntity(); - samlResponseLogEntity.setRequest(request.toString()); - samlResponseLogEntity.setResponse(response.toString()); - samlResponseLogEntity.setAuthenticationObject(authentication.toString()); - samlResponseLogRepository.save(samlResponseLogEntity); - try { - ObjectMapper objectMapper = new ObjectMapper(); - // Create a new SAML log entity - SamlResponseLogEntity samlResponseLogEntity1 = new SamlResponseLogEntity(); + try { + // Cast the authentication object to Saml2Authentication + Saml2Authentication samlAuth = (Saml2Authentication) authentication; + Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) samlAuth.getPrincipal(); - // Convert request, response, and authentication to JSON format - String requestJson = objectMapper.writeValueAsString(request.getParameterMap()); // Assuming request params to JSON - String responseJson = objectMapper.writeValueAsString(response); // This may need to be adapted based on your response object - String authenticationJson = objectMapper.writeValueAsString(authentication); // Authentication object to JSON + // Extract the user attributes from the principal + Map> userAttributes = principal.getAttributes(); - // Set the JSON strings in the entity - samlResponseLogEntity1.setRequest(requestJson); - samlResponseLogEntity1.setResponse(responseJson); - samlResponseLogEntity1.setAuthenticationObject(authenticationJson); - samlResponseLogRepository.save(samlResponseLogEntity1); - - logger.info("SAML Request: " + requestJson); - logger.info("SAML Response: " + responseJson); - logger.info("Authentication Details: " + authenticationJson); - }catch(Exception e) { - logger.info("Exception object" + e); - } -// samlResponseLogRepository - logger.info("SAML login successful for user: " + authentication.getName()); - response.sendRedirect("http://gepafin-staging-fe.s3-website.eu-central-1.amazonaws.com/"); - }).failureHandler((request, response, exception) -> { - logger.error("SAML login failed: " + exception.getMessage()); + // Log the user attributes for debugging purposes + logger.info("SAML User Attributes: " + userAttributes); - SamlResponseLogEntity samlResponseLogEntity = new SamlResponseLogEntity(); - samlResponseLogEntity.setRequest(request.toString()); - samlResponseLogEntity.setResponse(response.toString()); - samlResponseLogEntity.setExceptionObject(exception.toString()); - samlResponseLogRepository.save(samlResponseLogEntity); - try { - ObjectMapper objectMapper = new ObjectMapper(); + // Save the authentication details in the database (Optional) + SamlResponseLogEntity samlResponseLogEntity = new SamlResponseLogEntity(); + samlResponseLogEntity.setAuthenticationObject(authentication.toString()); - // Create a new SAML log entity - SamlResponseLogEntity samlResponseLogEntity1 = new SamlResponseLogEntity(); + // Convert user attributes to JSON and save in DB + ObjectMapper objectMapper = new ObjectMapper(); + String userAttributesJson = objectMapper.writeValueAsString(userAttributes); + samlResponseLogEntity.setAuthenticationObject(userAttributesJson); + samlResponseLogRepository.save(samlResponseLogEntity); + + // Successful login logic + logger.info("SAML login successful for user: " + principal.getName()); + response.sendRedirect("http://gepafin-staging-fe.s3-website.eu-central-1.amazonaws.com/login"); + } catch (Exception e) { + logger.error("Error processing SAML success handler", e); + } + }) + .failureHandler((request, response, exception) -> { + try { + logger.error("SAML login failed: " + exception.getMessage()); + + // Log the failure details to the database (Optional) + SamlResponseLogEntity samlResponseLogEntity = new SamlResponseLogEntity(); + samlResponseLogEntity.setRequest(request.toString()); + samlResponseLogEntity.setResponse(response.toString()); + samlResponseLogEntity.setExceptionObject(exception.toString()); + samlResponseLogRepository.save(samlResponseLogEntity); + + // Handle failure redirection + response.sendRedirect("http://gepafin-staging-fe.s3-website.eu-central-1.amazonaws.com/login"); + } catch (Exception e) { + logger.error("Error processing SAML failure handler", e); + } + }) + ); - // Convert request, response, and authentication to JSON format - String requestJson = objectMapper.writeValueAsString(request.getParameterMap()); // Assuming request params to JSON - String responseJson = objectMapper.writeValueAsString(response); // This may need to be adapted based on your response object - String exceptionJson = objectMapper.writeValueAsString(exception); // Authentication object to JSON - // Set the JSON strings in the entity - samlResponseLogEntity1.setRequest(requestJson); - samlResponseLogEntity1.setResponse(responseJson); - samlResponseLogEntity1.setAuthenticationObject(exceptionJson); - samlResponseLogRepository.save(samlResponseLogEntity1); - - logger.info("SAML Request: " + requestJson); - logger.info("SAML Response: " + responseJson); - logger.info("exception Details: " + exceptionJson); - }catch(Exception e) { - logger.info("Exception object" + e); - } - response.sendRedirect("http://gepafin-staging-fe.s3-website.eu-central-1.amazonaws.com/login"); - })); return http.build(); } @@ -263,26 +252,35 @@ public class SecurityConfig { @Bean public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() { - - String entityId = baseUrl + "/v1/saml/gw/metadata"; - String acsUrl = baseUrl + "/login/saml2/sso/loginumbria"; + + String entityId = baseUrl + "/v1/saml/gw/metadata"; + String acsUrl = baseUrl + "/login/saml2/sso/loginumbria"; + RelyingPartyRegistration registration = RelyingPartyRegistration.withRegistrationId("loginumbria") .entityId(entityId) - .signingX509Credentials(credentials -> { + .signingX509Credentials(credentials -> { + try { + credentials.add(Saml2X509Credential.signing(readPrivateKey(), readCertificate())); + } catch (Exception e) { + e.printStackTrace(); + } + }) + .assertionConsumerServiceLocation(acsUrl) + .assertingPartyDetails(details -> details.entityId("https://federatest.umbriadigitale.it/gw/metadata") + .singleSignOnServiceLocation("https://federatest.umbriadigitale.it/gw/SSOProxy/SAML2") + .singleSignOnServiceBinding(Saml2MessageBinding.POST) + .wantAuthnRequestsSigned(true) + .verificationX509Credentials(credentials -> { try { - credentials.add(Saml2X509Credential.signing(readPrivateKey(), readCertificate())); - // AuthnRequest signedAuthnRequest = createSignedAuthnRequest(readPrivateKey(), readCertificate()); - //logger.info("Signed SAML AuthnRequest: " + SamlRequestLogger.convertSAMLObjectToString(signedAuthnRequest)); + // Load the IDP's public certificate for verifying the SAML response signature + credentials.add(Saml2X509Credential.verification(readIdpCertificate())); } catch (Exception e) { e.printStackTrace(); } }) - .assertionConsumerServiceLocation(acsUrl) - .assertingPartyDetails(details -> details.entityId("https://federatest.umbriadigitale.it/gw/metadata") - .singleSignOnServiceLocation("https://federatest.umbriadigitale.it/gw/SSOProxy/SAML2") - .singleSignOnServiceBinding(Saml2MessageBinding.POST).wantAuthnRequestsSigned(true).build() - ) + ) .build(); + return new InMemoryRelyingPartyRegistrationRepository(registration); } @@ -378,6 +376,15 @@ private RequestedAuthnContext buildRequestedAuthnContext() { } } + public X509Certificate readIdpCertificate() throws Exception { + // Path to your IDP public certificate PEM file + try (InputStream inStream = readKey("dev/saml/idp-certificate.pem")) { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) certFactory.generateCertificate(inStream); + } + } + + public InputStream readKey(String path) throws IOException { ClassLoader classLoader = getClass().getClassLoader(); InputStream inputStream = classLoader.getResourceAsStream(path); diff --git a/src/main/resources/dev/saml/idp-certificate.pem b/src/main/resources/dev/saml/idp-certificate.pem new file mode 100644 index 00000000..598749d1 --- /dev/null +++ b/src/main/resources/dev/saml/idp-certificate.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIDJDCCAgygAwIBAgIVAIq/MUgxPKO0cuX/GtD7YUvk87GtMA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNVBAMTDmlkcC5tYWNoaW5lLml0MB4XDTA5MDMyNTEwNTM1OFoXDTI5MDMyNTA5NTM1OFowGTEXMBUGA1UEAxMOaWRwLm1hY2hpbmUuaXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClXV18x0/yhZ+D3pHlmhrK4paA+xdJKAT7U7R9DeaTQygwtCjKmCrJbzdohckLz5pax7eaGeA53pPCY+JdiU0Uq4ES8nG2DCZgCtl4QGLUcTuUtJdPq+DbYD1cWBwEeeffsiClVyuhgLRPO1OQLl/TJp4slfoYTi0aONgQp03uG+ixL48myL7GrINHYXtDUDqo2BimyU0yrOe6ZmvxJchZ8nBuWKy0J8wsO/Mnasbvo79/c8gcn0HTst0QDlHXQlzwZ4Suq2os9qKjXAYOzA1VqmTyzJIge/ynHiJ0Fkw0HNxBaVFTJRNL8RvwJsMuBT7YZKRoNK7gjT5/6bGagYM/AgMBAAGjYzBhMEAGA1UdEQQ5MDeCDmlkcC5tYWNoaW5lLml0hiVodHRwczovL2lkcC5tYWNoaW5lLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQWBBSBOsPZiWZRXFqNINIguHfv7jnidDANBgkqhkiG9w0BAQUFAAOCAQEAeVLN9jczRINuPUvpXbgibL2c99dUReMcl47nSVtYeYEBkPPZrSz0h3AyVZyar2Vo+/fC3fRNmaOJvfiVSm+bo1069iROI1+dGGq2gAwWuQI1q0F7PNPX4zooY+LbZI0oUhuoyH81xed0WtMlpJ1aRSBMpR6oV3rguAkH6pdr725yv6m5WxKcOM/LzdD5Xt9fQRL7ino4HfiPPJNDG3UOKhoAWkVn/Y/CuMLcBPWh/3LxIv4A1bQbnkpdty+Qtwfp4QUKkisv7gufQP91aLqUvvRE6Uz8r51VH13e4mEJjJGxLKXWzlP50gp7b27AXCTKSS6fW6iBpfA14PGcWvDiPQ== +-----END CERTIFICATE-----