diff --git a/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java b/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java index c6c56acfdb6..d0b8b855b38 100755 --- a/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java +++ b/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java @@ -48,7 +48,8 @@ public enum JBossSAMLConstants { "NameFormat"), NAMEID("NameID"), NAMEID_FORMAT("NameIDFormat"), NAMEID_MAPPING_SERVICE("NameIDMappingService"), NAMEID_POLICY( "NameIDPolicy"), NAME_QUALIFIER("NameQualifier"), NOT_BEFORE("NotBefore"), NOT_ON_OR_AFTER("NotOnOrAfter"), ORGANIZATION( "Organization"), ORGANIZATION_NAME("OrganizationName"), ORGANIZATION_DISPLAY_NAME("OrganizationDisplayName"), ORGANIZATION_URL( - "OrganizationURL"), PDP_DESCRIPTOR("PDPDescriptor"), PROTOCOL_BINDING("ProtocolBinding"), PROTOCOL_SUPPORT_ENUMERATION( + "OrganizationURL"), ORGANIZATION_URL_ALT( + "OrganizationUrl"), PDP_DESCRIPTOR("PDPDescriptor"), PROTOCOL_BINDING("ProtocolBinding"), PROTOCOL_SUPPORT_ENUMERATION( "protocolSupportEnumeration"), PROVIDER_NAME("ProviderName"), REQUESTED_AUTHN_CONTEXT("RequestedAuthnContext"), REASON( "Reason"), RECIPIENT("Recipient"), REQUEST("Request"), REQUESTED_ATTRIBUTE("RequestedAttribute"), REQUEST_ABSTRACT( "RequestAbstract"), RESPONSE("Response"), RESPONSE_LOCATION("ResponseLocation"), RETURN_CONTEXT("ReturnContext"), SESSION_INDEX( diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java index a0520abe50e..6759583f435 100755 --- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java +++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java @@ -400,7 +400,8 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme startElement = StaxParserUtil.getNextStartElement(xmlEventReader); LocalizedNameType localName = getLocalizedName(xmlEventReader, startElement); org.addOrganizationDisplayName(localName); - } else if (JBossSAMLConstants.ORGANIZATION_URL.get().equals(localPart)) { + } else if (JBossSAMLConstants.ORGANIZATION_URL.get().equals(localPart) || + (JBossSAMLConstants.ORGANIZATION_URL_ALT.get().equals(localPart))) { startElement = StaxParserUtil.getNextStartElement(xmlEventReader); Attribute lang = startElement.getAttributeByName(new QName(JBossSAMLURIConstants.XML.get(), "lang")); String langVal = StaxParserUtil.getAttributeValue(lang); diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java index ad150e96c5f..92f1a5ec8c8 100644 --- a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java +++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java @@ -16,12 +16,20 @@ */ package org.keycloak.saml.processing.core.parsers.saml; +import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType; + import java.io.InputStream; import org.junit.Test; + import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; + import org.keycloak.dom.saml.v2.protocol.LogoutRequestType; import org.keycloak.dom.saml.v2.protocol.ResponseType; + +import java.io.IOException; +import java.util.Scanner; +import org.junit.Before; import org.w3c.dom.Element; /** @@ -33,75 +41,86 @@ import org.w3c.dom.Element; */ public class SAMLParserTest { + private SAMLParser parser; + + @Before + public void initParser() { + this.parser = new SAMLParser(); + } + @Test public void testSaml20EncryptedAssertionsSignedReceivedWithRedirectBinding() throws Exception { - InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response.xml"); - SAMLParser parser = new SAMLParser(); + try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response.xml")) { + Object parsedObject = parser.parse(st); + assertThat(parsedObject, instanceOf(ResponseType.class)); - Object parsedObject = parser.parse(st); - assertThat(parsedObject, instanceOf(ResponseType.class)); - - ResponseType resp = (ResponseType) parsedObject; - assertThat(resp.getSignature(), nullValue()); - assertThat(resp.getConsent(), nullValue()); - assertThat(resp.getIssuer(), not(nullValue())); - assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo")); + ResponseType resp = (ResponseType) parsedObject; + assertThat(resp.getSignature(), nullValue()); + assertThat(resp.getConsent(), nullValue()); + assertThat(resp.getIssuer(), not(nullValue())); + assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo")); - assertThat(resp.getExtensions(), not(nullValue())); - assertThat(resp.getExtensions().getAny().size(), is(1)); - assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class)); - Element el = (Element) resp.getExtensions().getAny().get(0); - assertThat(el.getLocalName(), is("KeyInfo")); - assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0")); - assertThat(el.hasAttribute("MessageSigningKeyId"), is(true)); - assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE")); + assertThat(resp.getExtensions(), not(nullValue())); + assertThat(resp.getExtensions().getAny().size(), is(1)); + assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class)); + Element el = (Element) resp.getExtensions().getAny().get(0); + assertThat(el.getLocalName(), is("KeyInfo")); + assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0")); + assertThat(el.hasAttribute("MessageSigningKeyId"), is(true)); + assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE")); - assertThat(resp.getAssertions(), not(nullValue())); - assertThat(resp.getAssertions().size(), is(1)); + assertThat(resp.getAssertions(), not(nullValue())); + assertThat(resp.getAssertions().size(), is(1)); + } } @Test public void testSaml20EncryptedAssertionsSignedTwoExtensionsReceivedWithRedirectBinding() throws Exception { Element el; - InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response-two-extensions.xml"); - SAMLParser parser = new SAMLParser(); + try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response-two-extensions.xml")) { + Object parsedObject = parser.parse(st); + assertThat(parsedObject, instanceOf(ResponseType.class)); - Object parsedObject = parser.parse(st); - assertThat(parsedObject, instanceOf(ResponseType.class)); + ResponseType resp = (ResponseType) parsedObject; + assertThat(resp.getSignature(), nullValue()); + assertThat(resp.getConsent(), nullValue()); + assertThat(resp.getIssuer(), not(nullValue())); + assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo")); - ResponseType resp = (ResponseType) parsedObject; - assertThat(resp.getSignature(), nullValue()); - assertThat(resp.getConsent(), nullValue()); - assertThat(resp.getIssuer(), not(nullValue())); - assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo")); + assertThat(resp.getExtensions(), not(nullValue())); + assertThat(resp.getExtensions().getAny().size(), is(2)); + assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class)); + el = (Element) resp.getExtensions().getAny().get(0); + assertThat(el.getLocalName(), is("KeyInfo")); + assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0")); + assertThat(el.hasAttribute("MessageSigningKeyId"), is(true)); + assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE")); + assertThat(resp.getExtensions().getAny().get(1), instanceOf(Element.class)); + el = (Element) resp.getExtensions().getAny().get(1); + assertThat(el.getLocalName(), is("ever")); + assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:what:1.0")); + assertThat(el.hasAttribute("what"), is(true)); + assertThat(el.getAttribute("what"), is("ever")); - assertThat(resp.getExtensions(), not(nullValue())); - assertThat(resp.getExtensions().getAny().size(), is(2)); - assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class)); - el = (Element) resp.getExtensions().getAny().get(0); - assertThat(el.getLocalName(), is("KeyInfo")); - assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0")); - assertThat(el.hasAttribute("MessageSigningKeyId"), is(true)); - assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE")); - assertThat(resp.getExtensions().getAny().get(1), instanceOf(Element.class)); - el = (Element) resp.getExtensions().getAny().get(1); - assertThat(el.getLocalName(), is("ever")); - assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:what:1.0")); - assertThat(el.hasAttribute("what"), is(true)); - assertThat(el.getAttribute("what"), is("ever")); - - assertThat(resp.getAssertions(), not(nullValue())); - assertThat(resp.getAssertions().size(), is(1)); + assertThat(resp.getAssertions(), not(nullValue())); + assertThat(resp.getAssertions().size(), is(1)); + } } @Test public void testSaml20PostLogoutRequest() throws Exception { - InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-signed-logout-request.xml"); - SAMLParser parser = new SAMLParser(); - - Object parsedObject = parser.parse(st); - assertThat(parsedObject, instanceOf(LogoutRequestType.class)); + try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-signed-logout-request.xml")) { + Object parsedObject = parser.parse(st); + assertThat(parsedObject, instanceOf(LogoutRequestType.class)); + } + } + @Test + public void testOrganizationDetailsMetadata() throws Exception { + try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4040-sharefile-metadata.xml")) { + Object parsedObject = parser.parse(st); + assertThat(parsedObject, instanceOf(EntityDescriptorType.class)); + } } } diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4040-sharefile-metadata.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4040-sharefile-metadata.xml new file mode 100644 index 00000000000..7fe7824a27c --- /dev/null +++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4040-sharefile-metadata.xml @@ -0,0 +1,33 @@ + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + + + + + + + + + + + + + + Ldu0001hripzSq7zbIMTEKnQCOU= + + + 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 + + + + + ShareFile.com + ShareFile.com, a division of Citrix Systems, Inc + https://www.sharefile.com + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientDescriptionConverterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientDescriptionConverterTest.java new file mode 100644 index 00000000000..2718d3a8ca4 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientDescriptionConverterTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.keycloak.testsuite.admin.client; + +import org.keycloak.testsuite.AbstractAuthTest; + +import java.io.IOException; +import java.io.InputStream; +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +/** + * + * @author hmlnarik + */ +public class ClientDescriptionConverterTest extends AbstractAuthTest { + + // https://issues.jboss.org/browse/KEYCLOAK-4040 + @Test + public void testOrganizationDetailsMetadata() throws IOException { + try (InputStream is = ClientDescriptionConverterTest.class.getResourceAsStream("KEYCLOAK-4040-sharefile-metadata.xml")) { + String data = IOUtils.toString(is, "UTF-8"); + testRealmResource().convertClientDescription(data); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/admin/client/KEYCLOAK-4040-sharefile-metadata.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/admin/client/KEYCLOAK-4040-sharefile-metadata.xml new file mode 100644 index 00000000000..7fe7824a27c --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/admin/client/KEYCLOAK-4040-sharefile-metadata.xml @@ -0,0 +1,33 @@ + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + + + + + + + + + + + + + + Ldu0001hripzSq7zbIMTEKnQCOU= + + + J6IRDZ9RmdtpuwTlEK9HjqtbyeSA2Vz9mXF8yYRLIM0qMxRIvPLiIk02UuzCzEJ1I1xT4pcFuUfrdgDG6r9yf2iS+lV7jd0+DdXTHQ4VbQAZRC3Xd8wJ2RnnbZ3gwbIBBYurnWpKI0OCm0MnGvqV75n5Q6iF5jKA8Y4cFp60HHHnCH4QzpVTV5LjSg91eJA1X+99Xga+sK8Z+ln9wBzsrevz6ZfMt24rOMtb64wfAitz+HiD542Ta2TrzKQTnx+EPcr8xBwC62Gl+lIeE3DwKxtNk8pM8mq42D2b5UVKzjfL+PsYZ8XXBwwnwxFs40uxiI/ivq6KuQ/INt4Z5wmjGw== + + + MIIFUjCCBDqgAwIBAgIDBbH0MA0GCSqGSIb3DQEBBQUAMGExCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEbMBkGA1UEAxMSR2VvVHJ1c3QgRFYgU1NMIENBMB4XDTEyMTIxODAyMjcxOVoXDTE2MTIyMDAwNTYwMFowgckxKTAnBgNVBAUTIHlMbC1HNjFUWWtiaHBaL1JMTnNIYU8vTmJyWEVQOXc1MRMwEQYDVQQLEwpHVDQ4MjA0OTU4MTEwLwYDVQQLEyhTZWUgd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvY3BzIChjKTEyMTcwNQYDVQQLEy5Eb21haW4gQ29udHJvbCBWYWxpZGF0ZWQgLSBRdWlja1NTTChSKSBQcmVtaXVtMRswGQYDVQQDExJzYW1sLnNoYXJlZmlsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPUZyhTw3RmP7Y7v06aHgTNuv/Fm0PbGWbGlZEwqr8TGabocPbnb8iTBWAL2ECXMbx+VrpaHiSOVxqC2Y/vDXOs+1r0CzRKeMC6oQPsXZbieW6HxOAv3UVShxc9nfWI6+immo/o3BYI5WKcOaeZieVlDq7a7ctfSUJXHEBhpaSJNhghb+cUZtp1/EXs8/LyVQ31coo1q726WjCvFVB8OUU2u6BQLcbJF5aG3qh5CkNyivwM3NtNAyHhSXRmwyE+Yv5YNo5QAtUagCGYmS2saEJj8FxhXsNRtfW5B6vVhgmNreTcHCcWTpFGhjvferPjsjaIQAs3P2zx/pW/GSCXHy1AgMBAAGjggGoMIIBpDAfBgNVHSMEGDAWgBSM9NmTCke8AKBKzkt1bqC2sLJ+/DAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdEQQWMBSCEnNhbWwuc2hhcmVmaWxlLmNvbTBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vZ3Rzc2xkdi1jcmwuZ2VvdHJ1c3QuY29tL2NybHMvZ3Rzc2xkdi5jcmwwHQYDVR0OBBYEFIDTam2PfOzLpQoclHMwfsUtSi3kMAwGA1UdEwEB/wQCMAAwdQYIKwYBBQUHAQEEaTBnMCwGCCsGAQUFBzABhiBodHRwOi8vZ3Rzc2xkdi1vY3NwLmdlb3RydXN0LmNvbTA3BggrBgEFBQcwAoYraHR0cDovL2d0c3NsZHYtYWlhLmdlb3RydXN0LmNvbS9ndHNzbGR2LmNydDBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYwMzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczANBgkqhkiG9w0BAQUFAAOCAQEAU0I6sMe1ZgJ27pdu9qhQLMIgt0w7CuEbLfsSZZdo5TXEj15SGQwU2A0F6o5ivdAvMWTCISJsjHdqCkvB6ZOdMHIfSqA9ARLqX7wLKYfM8X/4RM3koHfqHOvxXBLqCLj2mn34oZrMU5CVI6rqbMoU4D61io7DVswR7Dss0rCh1b1o52ZEBjy5w9oJhRTEFwL7ekf6tR9UioyxQ37pGfD8qOpX1hj5gqcZ5+qUSVNjOjeh+9e9OO5Y/ns3jjHK5ieZPdYeLLOp+D6qzAnOERgvKvkPyRIHZA9tAjxj5KIEzQUopmbP7oH4Ovo6YXT+iIuMVvX3dDu00ExOSZjEeDzo/w== + + + + + ShareFile.com + ShareFile.com, a division of Citrix Systems, Inc + https://www.sharefile.com + + \ No newline at end of file