/* * ***************************************************************************** * Cloud Foundry * Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. * ***************************************************************************** */ package org.cloudfoundry.identity.uaa.provider.saml; import org.cloudfoundry.identity.uaa.cache.ExpiringUrlCache; import org.cloudfoundry.identity.uaa.constants.OriginKeys; import org.cloudfoundry.identity.uaa.provider.IdentityProvider; import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning; import org.cloudfoundry.identity.uaa.provider.SamlIdentityProviderDefinition; import org.cloudfoundry.identity.uaa.util.TimeServiceImpl; import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.opensaml.DefaultBootstrap; import org.opensaml.xml.parse.BasicParserPool; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.security.saml.metadata.ExtendedMetadataDelegate; import org.springframework.security.saml.trust.httpclient.TLSProtocolSocketFactory; import java.util.Arrays; import java.util.List; import java.util.Timer; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class SamlIdentityProviderConfiguratorTests { @BeforeClass public static void initializeOpenSAML() throws Exception { if (!org.apache.xml.security.Init.isInitialized()) { DefaultBootstrap.bootstrap(); } } public static final String xmlWithoutID = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"%s\"><md:IDPSSODescriptor WantAuthnRequestsSigned=\"true\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"><md:KeyDescriptor use=\"signing\"><ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"><ds:X509Data><ds:X509Certificate>MIICmTCCAgKgAwIBAgIGAUPATqmEMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYDVQQGEwJVUzETMBEG\n" + "A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU\n" + "MBIGA1UECwwLU1NPUHJvdmlkZXIxEDAOBgNVBAMMB1Bpdm90YWwxHDAaBgkqhkiG9w0BCQEWDWlu\n" + "Zm9Ab2t0YS5jb20wHhcNMTQwMTIzMTgxMjM3WhcNNDQwMTIzMTgxMzM3WjCBjzELMAkGA1UEBhMC\n" + "VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoM\n" + "BE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRAwDgYDVQQDDAdQaXZvdGFsMRwwGgYJKoZIhvcN\n" + "AQkBFg1pbmZvQG9rdGEuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeil67/TLOiTZU\n" + "WWgW2XEGgFZ94bVO90v5J1XmcHMwL8v5Z/8qjdZLpGdwI7Ph0CyXMMNklpaR/Ljb8fsls3amdT5O\n" + "Bw92Zo8ulcpjw2wuezTwL0eC0wY/GQDAZiXL59npE6U+fH1lbJIq92hx0HJSru/0O1q3+A/+jjZL\n" + "3tL/SwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAI5BoWZoH6Mz9vhypZPOJCEKa/K+biZQsA4Zqsuk\n" + "vvphhSERhqk/Nv76Vkl8uvJwwHbQrR9KJx4L3PRkGCG24rix71jEuXVGZUsDNM3CUKnARx4MEab6\n" + "GFHNkZ6DmoT/PFagngecHu+EwmuDtaG0rEkFrARwe+d8Ru0BN558abFb</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://pivotal.oktapreview.com/app/pivotal_pivotalcfstaging_1/k2lw4l5bPODCMIIDBRYZ/sso/saml\"/><md:SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"https://pivotal.oktapreview.com/app/pivotal_pivotalcfstaging_1/k2lw4l5bPODCMIIDBRYZ/sso/saml\"/></md:IDPSSODescriptor></md:EntityDescriptor>\n"; public static final String xml = String.format(xmlWithoutID, "http://www.okta.com/k2lw4l5bPODCMIIDBRYZ"); public static final String xmlWithoutHeader = xmlWithoutID.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", ""); public static final String singleAddAlias = "sample-alias"; private SamlIdentityProviderConfigurator configurator; private BootstrapSamlIdentityProviderConfigurator bootstrap; SamlIdentityProviderDefinition singleAdd = null; SamlIdentityProviderDefinition singleAddWithoutHeader = null; IdentityProviderProvisioning provisioning = mock(IdentityProviderProvisioning.class); @Before public void setUp() throws Exception { bootstrap = new BootstrapSamlIdentityProviderConfigurator(); configurator = new SamlIdentityProviderConfigurator(); configurator.setParserPool(new BasicParserPool()); singleAdd = new SamlIdentityProviderDefinition() .setMetaDataLocation(String.format(BootstrapSamlIdentityProviderConfiguratorTests.xmlWithoutID, new RandomValueStringGenerator().generate())) .setIdpEntityAlias(singleAddAlias) .setNameID("sample-nameID") .setAssertionConsumerIndex(1) .setMetadataTrustCheck(true) .setLinkText("sample-link-test") .setIconUrl("sample-icon-url") .setZoneId("uaa"); singleAddWithoutHeader = new SamlIdentityProviderDefinition() .setMetaDataLocation(String.format(xmlWithoutHeader, new RandomValueStringGenerator().generate())) .setIdpEntityAlias(singleAddAlias) .setNameID("sample-nameID") .setAssertionConsumerIndex(1) .setMetadataTrustCheck(true) .setLinkText("sample-link-test") .setIconUrl("sample-icon-url") .setZoneId("uaa"); configurator.setIdentityProviderProvisioning(provisioning); configurator.setContentCache(new ExpiringUrlCache(1000*60*10, new TimeServiceImpl(), 100)); } /*@Test @Ignore public void testSingleAddProviderWithoutXMLHeader() throws Exception { ExtendedMetadataDelegate[] result = configurator.validateSamlIdentityProviderDefinition(singleAddWithoutHeader); assertNotNull(result); assertEquals(2, result.length); assertNotNull(result[0]); assertNull(result[1]); }*/ @Test(expected = NullPointerException.class) public void testAddNullProvider() throws Exception { configurator.validateSamlIdentityProviderDefinition(null); } @Test(expected = NullPointerException.class) public void testAddNullProviderAlias() throws Exception { singleAdd.setIdpEntityAlias(null); configurator.validateSamlIdentityProviderDefinition(singleAdd); } @Test public void testGetEntityID() throws Exception { Timer t = new Timer(); bootstrap.setIdentityProviders(BootstrapSamlIdentityProviderConfiguratorTests.parseYaml(BootstrapSamlIdentityProviderConfiguratorTests.sampleYaml)); bootstrap.afterPropertiesSet(); for (SamlIdentityProviderDefinition def : bootstrap.getIdentityProviderDefinitions()) { switch (def.getIdpEntityAlias()) { case "okta-local" : { ComparableProvider provider = (ComparableProvider) configurator.getExtendedMetadataDelegateFromCache(def).getDelegate(); assertEquals("http://www.okta.com/k2lvtem0VAJDMINKEYJW", provider.getEntityID()); break; } case "okta-local-3" : { ComparableProvider provider = (ComparableProvider) configurator.getExtendedMetadataDelegateFromCache(def).getDelegate(); assertEquals("http://www.okta.com/k2lvtem0VAJDMINKEYJX", provider.getEntityID()); break; } case "okta-local-2" : { ComparableProvider provider = (ComparableProvider) configurator.getExtendedMetadataDelegateFromCache(def).getDelegate(); assertEquals("http://www.okta.com/k2lw4l5bPODCMIIDBRYZ", provider.getEntityID()); break; } case "simplesamlphp-url" : { ComparableProvider provider = (ComparableProvider) configurator.getExtendedMetadataDelegateFromCache(def).getDelegate(); assertEquals("http://simplesamlphp.identity.cf-app.com/saml2/idp/metadata.php", provider.getEntityID()); break; } default: fail(String.format("Unknown provider %s", def.getIdpEntityAlias())); } } t.cancel(); } @Test public void testIdentityProviderDefinitionSocketFactoryTest() { singleAdd.setMetaDataLocation("http://www.test.org/saml/metadata"); assertNull(singleAdd.getSocketFactoryClassName()); singleAdd.setMetaDataLocation("https://www.test.org/saml/metadata"); assertNull(singleAdd.getSocketFactoryClassName()); singleAdd.setSocketFactoryClassName(TLSProtocolSocketFactory.class.getName()); assertNull(singleAdd.getSocketFactoryClassName()); } protected List<SamlIdentityProviderDefinition> getSamlIdentityProviderDefinitions(List<String> clientIdpAliases ) { SamlIdentityProviderDefinition def1 = new SamlIdentityProviderDefinition() .setMetaDataLocation(xml) .setIdpEntityAlias("simplesamlphp-url") .setNameID("sample-nameID") .setAssertionConsumerIndex(1) .setMetadataTrustCheck(true) .setLinkText("sample-link-test") .setIconUrl("sample-icon-url") .setZoneId("other-zone-id"); IdentityProvider idp1 = mock(IdentityProvider.class); when(idp1.getType()).thenReturn(OriginKeys.SAML); when(idp1.getConfig()).thenReturn(def1); IdentityProvider idp2 = mock(IdentityProvider.class); when(idp2.getType()).thenReturn(OriginKeys.SAML); when(idp2.getConfig()).thenReturn(def1.clone().setIdpEntityAlias("okta-local-2")); IdentityProvider idp3 = mock(IdentityProvider.class); when(idp3.getType()).thenReturn(OriginKeys.SAML); when(idp3.getConfig()).thenReturn(def1.clone().setIdpEntityAlias("okta-local-3")); when(provisioning.retrieveActive(anyString())).thenReturn(Arrays.asList(idp1, idp2)); return configurator.getIdentityProviderDefinitions(clientIdpAliases, IdentityZoneHolder.get()); } @Test public void testGetIdentityProviderDefinititonsForAllowedProviders() throws Exception { List<String> clientIdpAliases = asList("simplesamlphp-url", "okta-local-2"); List<SamlIdentityProviderDefinition> clientIdps = getSamlIdentityProviderDefinitions(clientIdpAliases); assertEquals(2, clientIdps.size()); assertTrue(clientIdpAliases.contains(clientIdps.get(0).getIdpEntityAlias())); assertTrue(clientIdpAliases.contains(clientIdps.get(1).getIdpEntityAlias())); } @Test public void testReturnNoIdpsInZoneForClientWithNoAllowedProviders() throws Exception { List<String> clientIdpAliases = asList("non-existent"); List<SamlIdentityProviderDefinition> clientIdps = getSamlIdentityProviderDefinitions(clientIdpAliases); assertEquals(0, clientIdps.size()); } }