package at.asitplus.eidas.specific.connector.test; import static org.mockito.ArgumentMatchers.any; import static org.powermock.api.mockito.PowerMockito.when; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.net.URISyntaxException; import java.time.Instant; import java.util.Map; import java.util.Timer; import javax.xml.transform.TransformerException; import org.apache.commons.lang3.RandomStringUtils; import org.apache.ignite.Ignition; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.MarshallingException; import org.opensaml.core.xml.io.UnmarshallingException; import org.opensaml.core.xml.util.XMLObjectSupport; import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.core.io.ResourceLoader; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.util.Base64Utils; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.github.skjolber.mockito.soap.SoapServiceRule; import at.asitplus.eidas.specific.connector.controller.ProcessEngineSignalController; import at.asitplus.eidas.specific.connector.controller.Pvp2SProfileEndpoint; import at.asitplus.eidas.specific.connector.provider.PvpEndPointCredentialProvider; import at.asitplus.eidas.specific.connector.provider.PvpMetadataProvider; import at.asitplus.eidas.specific.connector.test.saml2.Pvp2SProfileEndPointTest; import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasSignalServlet; import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; import at.gv.egiz.components.spring.api.SpringBootApplicationContextInitializer; import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.idp.controller.ProtocolFinalizationController; import at.gv.egiz.eaaf.core.impl.utils.DomUtils; import at.gv.egiz.eaaf.core.impl.utils.Random; import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor; import eu.eidas.auth.cache.IgniteInstanceInitializerSpecificCommunication; import eu.eidas.auth.commons.attribute.AttributeDefinition; import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; import eu.eidas.auth.commons.light.ILightRequest; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; import eu.eidas.auth.commons.tx.BinaryLightToken; import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; import eu.eidas.specificcommunication.exception.SpecificCommunicationException; import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; import lombok.val; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.xml.XMLParserException; import szrservices.SZR; import szrservices.SignContentEntry; import szrservices.SignContentResponseType; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest @ContextConfiguration(initializers = { org.springframework.boot.context.config.DelegatingApplicationContextInitializer.class, SpringBootApplicationContextInitializer.class }) @TestPropertySource(locations = { "file:src/test/resources/config/junit_config_1_springboot.properties" }) @DirtiesContext(classMode = ClassMode.AFTER_CLASS) @ActiveProfiles(profiles = {"JUNIT", "jUnitTestMode"}) public class FullStartUpAndProcessTest { private static final String FINAL_REDIRECT = "http://localhost/public/secure/finalizeAuthProtocol?pendingid="; @Autowired private WebApplicationContext wac; @Autowired private PvpEndPointCredentialProvider credentialProvider; @Autowired private PvpMetadataProvider metadataProvider; @Autowired private ResourceLoader resourceLoader; @Autowired private EidasAttributeRegistry attrRegistry; @Autowired private Pvp2SProfileEndpoint sProfile; @Autowired private ProcessEngineSignalController signal; @Autowired private EidasSignalServlet eidasSignal; @Autowired private ProtocolFinalizationController finalize; @Rule public final SoapServiceRule soap = SoapServiceRule.newInstance(); private SZR szrMock; private String cc; private String givenName; private String familyName; private String dateOfBirth; private String personalId; private String vsz; private String eidasBind; /** * jUnit class initializer. * @throws InterruptedException In case of an error * @throws ComponentInitializationException In case of an error * @throws InitializationException In case of an error * */ @BeforeClass public static void classInitializer() throws InterruptedException, InitializationException, ComponentInitializationException { final String current = new java.io.File(".").toURI().toString(); System.clearProperty("eidas.ms.configuration"); //eIDAS Ref. Impl. properties System.setProperty("EIDAS_CONFIG_REPOSITORY", current.substring("file:".length()) + "../basicConfig/eIDAS/"); System.setProperty("SPECIFIC_CONNECTOR_CONFIG_REPOSITORY", current.substring("file:".length()) + "../basicConfig/eIDAS/"); System.setProperty("SPECIFIC_PROXY_SERVICE_CONFIG_REPOSITORY", current.substring("file:".length()) + "../basicConfig/eIDAS/"); EaafOpenSaml3xInitializer.eaafInitialize(); } /** * Test shut-down. * * @throws Exception In case of an error */ @AfterClass public static void closeIgniteNode() throws Exception { System.out.println("Closiong Ignite Node ... "); Ignition.stopAll(true); //set Ignite-node holder to 'null' because static holders are shared between different tests final Field field = IgniteInstanceInitializerSpecificCommunication.class.getDeclaredField("instance"); field.setAccessible(true); field.set(null, null); } /** * jUnit test set-up. * * */ @Before public void setup() throws IOException { DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac); @SuppressWarnings("rawtypes") Map filters = wac.getBeansOfType(FilterRegistrationBean.class); for (FilterRegistrationBean filter : filters.values()) { if (filter.isEnabled()) { builder.addFilter(filter.getFilter(), "/*"); } } szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); personalId = cc + "/AT/" + RandomStringUtils.randomNumeric(64); familyName = RandomStringUtils.randomAlphabetic(10); givenName = RandomStringUtils.randomAlphabetic(10); dateOfBirth = "2015-10-12"; vsz = RandomStringUtils.randomNumeric(10); eidasBind = RandomStringUtils.randomAlphanumeric(50); } @Test public void userStopProcess() throws UnsupportedEncodingException, XMLParserException, UnmarshallingException, TransformerException, IOException, MarshallingException, ComponentInitializationException, EaafException { //start authentication process by sending a SAML2 Authn-Request MockHttpServletRequest saml2Req = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); injectSaml2AuthnReq(saml2Req); MockHttpServletResponse selectCountryResp = new MockHttpServletResponse(); RequestContextHolder.resetRequestAttributes(); RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(saml2Req, selectCountryResp)); // send SAML2 AuthnRequest sProfile.pvpIdpPostRequest(saml2Req, selectCountryResp); //check country-selection response Assert.assertEquals("no country-selection page", 200, selectCountryResp.getStatus()); Assert.assertEquals("cc-selection page", "text/html;charset=UTF-8", selectCountryResp.getContentType()); String selectionPage = selectCountryResp.getContentAsString(); Assert.assertNotNull("selectionPage is null", selectionPage); Assert.assertFalse("selectionPage is empty", selectionPage.isEmpty()); String pendingReqId = extractRequestToken(selectionPage, " attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( Constants.eIDAS_ATTR_DATEOFBIRTH).first(); final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() .put(attributeDef, personalId) .put(attributeDef2, familyName) .put(attributeDef3, givenName) .put(attributeDef4, dateOfBirth).build(); val b = new AuthenticationResponse.Builder(); return b.id("_".concat(Random.nextHexRandom16())) .issuer(RandomStringUtils.randomAlphabetic(10)) .subject(RandomStringUtils.randomAlphabetic(10)) .statusCode(statusCode) .inResponseTo(reqId) .subjectNameIdFormat("afaf") .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) .attributes(attributeMap) .build(); } private String extractRequestToken(String selectionPage, String selector) { int start = selectionPage.indexOf(selector); Assert.assertTrue("find no pendingReqId location start", start > 0); int end = selectionPage.indexOf("\"", start + selector.length()); Assert.assertTrue("find no pendingReqId location end", end > 0); return selectionPage.substring(start + selector.length(), end); } private void injectSaml2AuthnReq(MockHttpServletRequest saml2Req) throws XMLParserException, UnmarshallingException, SamlSigningException, CredentialsNotAvailableException, UnsupportedEncodingException, TransformerException, IOException, MarshallingException, ComponentInitializationException { final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( XMLObjectProviderRegistrySupport.getParserPool(), Pvp2SProfileEndPointTest.class.getResourceAsStream("/data/pvp2_authn_1.xml")); authnReq.setIssueInstant(Instant.now()); RequestAbstractType signedAuthnReq = Saml2Utils.signSamlObject(authnReq, credentialProvider.getMessageSigningCredential(), true); String b64 = Base64Utils.encodeToString(DomUtils.serializeNode( XMLObjectSupport.getMarshaller(signedAuthnReq).marshall(signedAuthnReq)).getBytes("UTF-8")); saml2Req.setParameter("SAMLRequest", b64); final org.springframework.core.io.Resource resource = resourceLoader.getResource( "classpath:/data/metadata_valid_without_encryption.xml"); Timer timer = new Timer("PVP metadata-resolver refresh"); ResourceBackedMetadataResolver fileSystemResolver = new ResourceBackedMetadataResolver(timer, new OpenSaml3ResourceAdapter(resource)); fileSystemResolver.setId("test"); fileSystemResolver.setParserPool(XMLObjectProviderRegistrySupport.getParserPool()); fileSystemResolver.initialize(); metadataProvider.addMetadataResolverIntoChain(fileSystemResolver); } }