keycloak-aplcache
Changes
saml-core/pom.xml 31(+30 -1)
saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SecurityActions.java 93(+0 -93)
saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SecurityActions.java 160(+0 -160)
saml-core/src/main/java/org/keycloak/saml/processing/web/util/RedirectBindingSignatureUtil.java 344(+0 -344)
Details
saml-core/pom.xml 31(+30 -1)
diff --git a/saml-core/pom.xml b/saml-core/pom.xml
index a198733..0914083 100755
--- a/saml-core/pom.xml
+++ b/saml-core/pom.xml
@@ -32,6 +32,7 @@
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
+ <skip.security-manager.tests>true</skip.security-manager.tests>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
</properties>
<dependencies>
@@ -56,7 +57,6 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -88,6 +88,35 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>without-security-manager</id>
+ <goals><goal>test</goal></goals>
+ <configuration></configuration>
+ </execution>
+ <execution>
+ <id>with-security-manager-all-permissions</id>
+ <goals><goal>test</goal></goals>
+ <configuration>
+ <argLine>-Dmaven.basedir=${basedir} -Djava.security.manager -Djava.security.policy=${basedir}/src/test/resources/all-permissions.policy</argLine>
+ <test>SecurityActionsTest</test>
+ <skip>${skip.security-manager.tests}</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <id>with-security-manager-named-permissions</id>
+ <goals><goal>test</goal></goals>
+ <configuration>
+ <argLine>-Djava.security.debug=access -Dmaven.basedir=${basedir} -Djava.security.manager -Djava.security.policy=${basedir}/src/test/resources/named-permissions.policy</argLine>
+ <test>SecurityActionsTest</test>
+ <skip>${skip.security-manager.tests}</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/SecurityActions.java b/saml-core/src/main/java/org/keycloak/saml/common/util/SecurityActions.java
index b36adb4..b4a6279 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/SecurityActions.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/SecurityActions.java
@@ -19,6 +19,7 @@ package org.keycloak.saml.common.util;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.PropertyPermission;
/**
* Privileged Blocks
@@ -28,6 +29,14 @@ import java.security.PrivilegedAction;
*/
public class SecurityActions {
+ private static String extractPackageNameFromClassName(final String fullyQualifiedName) {
+ final int lastDot = fullyQualifiedName.lastIndexOf('.');
+ if (lastDot == -1) {
+ return "";
+ }
+ return fullyQualifiedName.substring(0, lastDot);
+ }
+
/**
* <p> Loads a {@link Class} using the <code>fullQualifiedName</code> supplied. This method tries first to load from
* the specified {@link Class}, if not found it will try to load from using TCL. </p>
@@ -37,11 +46,17 @@ public class SecurityActions {
*
* @return
*/
- static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
+ public static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
SecurityManager sm = System.getSecurityManager();
+ if (fullQualifiedName == null) {
+ return null;
+ }
+
if (sm != null) {
+ sm.checkPackageDefinition(extractPackageNameFromClassName(fullQualifiedName));
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
+ @Override
public Class<?> run() {
ClassLoader classLoader = theClass.getClassLoader();
@@ -73,11 +88,17 @@ public class SecurityActions {
*
* @return
*/
- static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
+ public static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
SecurityManager sm = System.getSecurityManager();
+ if (fullQualifiedName == null) {
+ return null;
+ }
+
if (sm != null) {
+ sm.checkPackageDefinition(extractPackageNameFromClassName(fullQualifiedName));
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
+ @Override
public Class<?> run() {
try {
return classLoader.loadClass(fullQualifiedName);
@@ -103,13 +124,14 @@ public class SecurityActions {
*
* @return
*/
- static URL loadResource(final Class<?> clazz, final String resourceName) {
+ public static URL loadResource(final Class<?> clazz, final String resourceName) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return AccessController.doPrivileged(new PrivilegedAction<URL>() {
+ @Override
public URL run() {
- URL url = null;
+ URL url;
ClassLoader clazzLoader = clazz.getClassLoader();
url = clazzLoader.getResource(resourceName);
@@ -122,7 +144,7 @@ public class SecurityActions {
}
});
} else {
- URL url = null;
+ URL url;
ClassLoader clazzLoader = clazz.getClassLoader();
url = clazzLoader.getResource(resourceName);
@@ -143,11 +165,13 @@ public class SecurityActions {
*
* @return
*/
- static void setSystemProperty(final String key, final String value) {
+ public static void setSystemProperty(final String key, final String value) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
+ sm.checkPermission(new PropertyPermission(key, "write"));
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
System.setProperty(key, value);
return null;
@@ -167,11 +191,13 @@ public class SecurityActions {
*
* @return
*/
- static String getSystemProperty(final String key, final String defaultValue) {
+ public static String getSystemProperty(final String key, final String defaultValue) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
+ sm.checkPermission(new PropertyPermission(key, "read"));
return AccessController.doPrivileged(new PrivilegedAction<String>() {
+ @Override
public String run() {
return System.getProperty(key, defaultValue);
}
@@ -188,7 +214,9 @@ public class SecurityActions {
*/
public static ClassLoader getTCCL() {
if (System.getSecurityManager() != null) {
+ System.getSecurityManager().checkPermission(new RuntimePermission("getClassLoader"));
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ @Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
@@ -205,7 +233,9 @@ public class SecurityActions {
*/
public static void setTCCL(final ClassLoader paramCl) {
if (System.getSecurityManager() != null) {
+ System.getSecurityManager().checkPermission(new RuntimePermission("setContextClassLoader"));
AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
public Void run() {
Thread.currentThread().setContextClassLoader(paramCl);
return null;
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/StaxUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/StaxUtil.java
index 3c5cd38..f10ecf5 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/StaxUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/StaxUtil.java
@@ -46,7 +46,7 @@ public class StaxUtil {
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
- private static ThreadLocal<Stack<String>> registeredNSStack = new ThreadLocal<Stack<String>>();
+ private static final ThreadLocal<Stack<String>> registeredNSStack = new ThreadLocal<Stack<String>>();
/**
* Flush the stream writer
@@ -341,10 +341,10 @@ public class StaxUtil {
writeStartElement(writer, domElementPrefix, domElement.getLocalName(), domElementNS);
// Should we register namespace
- if (domElementPrefix != "" && !registeredNSStack.get().contains(domElementNS)) {
+ if (! domElementPrefix.isEmpty() && !registeredNSStack.get().contains(domElementNS)) {
// writeNameSpace(writer, domElementPrefix, domElementNS );
registeredNSStack.get().push(domElementNS);
- } else if (domElementPrefix == "" && domElementNS != null) {
+ } else if (domElementPrefix.isEmpty() && ! domElementNS.isEmpty()) {
writeNameSpace(writer, "xmlns", domElementNS);
}
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/StringUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/StringUtil.java
index 23fb45f..366d739 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/StringUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/StringUtil.java
@@ -59,55 +59,6 @@ public class StringUtil {
return str == null || str.isEmpty();
}
- private static final Pattern PROPERTY_REPLACEMENT = Pattern.compile("(.*?)" + "\\$\\{(.*?)" + "(?:::(.*?))?\\}");
- // 1: PREFIX | START 2: NAME | 3: OPTIONAL DEFAULT VALUE
-
- /**
- * <p>
- * Get the system property value if the string is of the format ${sysproperty}
- * </p>
- * <p>
- * You can insert default value when the system property is not set, by separating it at the beginning with ::
- * </p>
- * <p>
- * <b>Examples:</b>
- * </p>
- *
- * <p>
- * ${idp} should resolve to a value if the system property "idp" is set.
- * </p>
- * <p>
- * ${idp::http://localhost:8080} will resolve to http://localhost:8080 if the system property "idp" is not set.
- * </p>
- *
- * @param str
- *
- * @return
- */
- public static String getSystemPropertyAsString(String str) {
- if (str == null)
- throw logger.nullArgumentError("str");
-
- Matcher m = PROPERTY_REPLACEMENT.matcher(str);
- StringBuilder sb = new StringBuilder();
- int lastPosition = 0;
- while (m.find()) {
- String propertyName = m.group(2);
- String defaultValue = m.group(3);
-
- String sysPropertyValue = SecurityActions.getSystemProperty(propertyName, defaultValue);
- if (sysPropertyValue.isEmpty()) {
- throw logger.systemPropertyMissingError(propertyName);
- }
-
- sb.append(m.group(1)).append(sysPropertyValue);
-
- lastPosition = m.end();
- }
-
- return sb.append(str.substring(lastPosition)).toString();
- }
-
/**
* Match two strings else throw a {@link RuntimeException}
*
@@ -118,67 +69,4 @@ public class StringUtil {
if (!first.equals(second))
throw logger.notEqualError(first, second);
}
-
- /**
- * Given a comma separated string, get the tokens as a {@link List}
- *
- * @param str
- *
- * @return
- */
- public static List<String> tokenize(String str) {
- return tokenize(str, ",");
- }
-
- /**
- * Given a delimited string, get the tokens as a {@link List}
- *
- * @param str
- * @param delimiter the delimiter
- *
- * @return
- */
- public static List<String> tokenize(String str, String delimiter) {
- List<String> list = new ArrayList<String>();
- StringTokenizer tokenizer = new StringTokenizer(str, delimiter);
- while (tokenizer.hasMoreTokens()) {
- list.add(tokenizer.nextToken());
- }
- return list;
- }
-
- /**
- * Given a string that is comma delimited and contains key-value pairs
- *
- * @param keyValuePairString
- *
- * @return
- */
- public static Map<String, String> tokenizeKeyValuePair(String keyValuePairString) {
- Map<String, String> map = new HashMap<String, String>();
-
- List<String> tokens = tokenize(keyValuePairString);
- for (String token : tokens) {
- int location = token.indexOf('=');
- map.put(token.substring(0, location), token.substring(location + 1));
- }
- return map;
- }
-
- public static String[] split(String toSplit, String delimiter) {
- if (delimiter.length() != 1) {
- throw new IllegalArgumentException("Delimiter can only be one character in length");
- }
-
- int offset = toSplit.indexOf(delimiter);
-
- if (offset < 0) {
- return null;
- }
-
- String beforeDelimiter = toSplit.substring(0, offset);
- String afterDelimiter = toSplit.substring(offset + 1);
-
- return new String[]{beforeDelimiter, afterDelimiter};
- }
}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java
index 8510d47..7b45cae 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java
@@ -21,6 +21,7 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.SecurityActions;
import org.keycloak.saml.common.util.SystemPropertiesUtil;
import javax.xml.datatype.DatatypeConfigurationException;
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolver.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolver.java
index 299ddaa..fdfa448 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolver.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolver.java
@@ -16,6 +16,7 @@
*/
package org.keycloak.saml.processing.core.util;
+import org.keycloak.saml.common.util.SecurityActions;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXBUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXBUtil.java
index be255e2..bf2ecfe 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXBUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXBUtil.java
@@ -20,6 +20,7 @@ import org.keycloak.saml.common.PicketLinkLogger;
import org.keycloak.saml.common.PicketLinkLoggerFactory;
import org.keycloak.saml.common.constants.GeneralConstants;
+import org.keycloak.saml.common.util.SecurityActions;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
@@ -48,7 +49,7 @@ public class JAXBUtil {
public static final String W3C_XML_SCHEMA_NS_URI = "http://www.w3.org/2001/XMLSchema";
- private static HashMap<String, JAXBContext> jaxbContextHash = new HashMap<String, JAXBContext>();
+ private static final HashMap<String, JAXBContext> jaxbContextHash = new HashMap<String, JAXBContext>();
static {
// Useful on Sun VMs. Harmless on other VMs.
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXPValidationUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXPValidationUtil.java
index 49e6ce3..49d531c 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXPValidationUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/JAXPValidationUtil.java
@@ -21,6 +21,7 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.common.util.DocumentUtil;
+import org.keycloak.saml.common.util.SecurityActions;
import org.keycloak.saml.common.util.SystemPropertiesUtil;
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/ProvidersUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/ProvidersUtil.java
index 5918737..e4369a2 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/ProvidersUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/ProvidersUtil.java
@@ -19,6 +19,7 @@ package org.keycloak.saml.processing.core.util;
import org.keycloak.saml.common.PicketLinkLogger;
import org.keycloak.saml.common.PicketLinkLoggerFactory;
+import org.keycloak.saml.common.util.SecurityActions;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Provider;
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
index 85ddf2c..6c07790 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
@@ -88,6 +88,7 @@ import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.dsig.keyinfo.KeyName;
import org.keycloak.rotation.KeyLocator;
+import org.keycloak.saml.common.util.SecurityActions;
import org.keycloak.saml.processing.api.util.KeyInfoTools;
/**
diff --git a/saml-core/src/test/java/org/keycloak/saml/common/util/SecurityActionsTest.java b/saml-core/src/test/java/org/keycloak/saml/common/util/SecurityActionsTest.java
new file mode 100644
index 0000000..0b0a0a6
--- /dev/null
+++ b/saml-core/src/test/java/org/keycloak/saml/common/util/SecurityActionsTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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.saml.common.util;
+
+import java.security.AccessControlException;
+import java.security.AllPermission;
+import java.security.Policy;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class SecurityActionsTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private static final boolean RESTRICTED = System.getSecurityManager() != null && ! Policy.getPolicy().implies(SecurityActionsTest.class.getProtectionDomain(), new AllPermission());
+
+ @Test
+ public void testLoadClass() {
+ SecurityActions.loadClass(SecurityActionsTest.class, "java.lang.String");
+ if (RESTRICTED) {
+ expectedException.expect(SecurityException.class);
+ }
+
+ // Must be a class from a package listed in package.definition property in java.security properties file
+ SecurityActions.loadClass(SecurityActions.class, "sun.misc.Unsafe");
+ }
+
+ @Test
+ public void testGetTCCL() {
+ if (RESTRICTED) {
+ expectedException.expect(AccessControlException.class);
+ }
+ SecurityActions.getTCCL();
+ }
+
+ @Test
+ public void testSetTCCL() {
+ if (RESTRICTED) {
+ expectedException.expect(AccessControlException.class);
+ }
+ SecurityActions.setTCCL(ClassLoader.getSystemClassLoader());
+ }
+
+}
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolverTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolverTest.java
index 48d6a0e..ecd8e6e 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolverTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/util/IDFedLSInputResolverTest.java
@@ -16,6 +16,7 @@
*/
package org.keycloak.saml.processing.core.util;
+import org.keycloak.saml.common.util.SecurityActions;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
diff --git a/saml-core/src/test/resources/all-permissions.policy b/saml-core/src/test/resources/all-permissions.policy
new file mode 100644
index 0000000..5d74bde
--- /dev/null
+++ b/saml-core/src/test/resources/all-permissions.policy
@@ -0,0 +1,3 @@
+grant {
+ permission java.security.AllPermission;
+};
\ No newline at end of file
diff --git a/saml-core/src/test/resources/named-permissions.policy b/saml-core/src/test/resources/named-permissions.policy
new file mode 100644
index 0000000..0d4ba1d
--- /dev/null
+++ b/saml-core/src/test/resources/named-permissions.policy
@@ -0,0 +1,15 @@
+grant {
+ permission java.io.FilePermission "<<ALL FILES>>", "read";
+ permission java.io.FilePermission "${maven.basedir}${/}-", "read,write,delete";
+
+ // SUREFIRE-859
+ permission "java.util.PropertyPermission" "*", "read,write";
+
+ permission "java.lang.RuntimePermission" "accessDeclaredMembers";
+ permission "java.lang.RuntimePermission" "getProtectionDomain";
+ permission "java.lang.RuntimePermission" "setIO";
+
+ permission "java.lang.RuntimePermission" "defineClassInPackage.java.lang";
+
+ permission "java.security.SecurityPermission" "getPolicy";
+};
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java b/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java
index d3cd904..59e32ef 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java
@@ -21,6 +21,8 @@ import org.keycloak.Config;
import org.keycloak.dom.saml.v2.metadata.EndpointType;
import org.keycloak.dom.saml.v2.metadata.EntitiesDescriptorType;
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
+import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType.EDTDescriptorChoiceType;
+import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
@@ -37,7 +39,6 @@ import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
import org.keycloak.saml.processing.core.saml.v2.util.SAMLMetadataUtil;
-import org.keycloak.saml.processing.core.util.CoreConfigUtil;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -46,6 +47,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -66,6 +68,41 @@ public class EntityDescriptorDescriptionConverter implements ClientDescriptionCo
return loadEntityDescriptors(new ByteArrayInputStream(description.getBytes()));
}
+ /**
+ * Get the SP Descriptor from an entity descriptor
+ *
+ * @param entityDescriptor
+ *
+ * @return
+ */
+ public static SPSSODescriptorType getSPDescriptor(EntityDescriptorType entityDescriptor) {
+ return entityDescriptor.getChoiceType().stream()
+ .flatMap(d -> d.getDescriptors().stream())
+ .map(EDTDescriptorChoiceType::getSpDescriptor)
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * Get the service url for the SP
+ *
+ * @param sp
+ * @param bindingURI
+ *
+ * @return
+ */
+ public static String getServiceURL(SPSSODescriptorType sp, String bindingURI) {
+ List<IndexedEndpointType> endpoints = sp.getAssertionConsumerService();
+ for (IndexedEndpointType endpoint : endpoints) {
+ if (Objects.equals(endpoint.getBinding().toString(), bindingURI)) {
+ return endpoint.getLocation().toString();
+ }
+
+ }
+ return null;
+ }
+
private static ClientRepresentation loadEntityDescriptors(InputStream is) {
Object metadata;
try {
@@ -104,7 +141,7 @@ public class EntityDescriptorDescriptionConverter implements ClientDescriptionCo
attributes.put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_EXT, SamlProtocol.ATTRIBUTE_FALSE_VALUE); // default to false
attributes.put(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM, SignatureAlgorithm.RSA_SHA256.toString());
attributes.put(SamlConfigAttributes.SAML_AUTHNSTATEMENT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
- SPSSODescriptorType spDescriptorType = CoreConfigUtil.getSPDescriptor(entity);
+ SPSSODescriptorType spDescriptorType = getSPDescriptor(entity);
if (spDescriptorType.isWantAssertionsSigned()) {
attributes.put(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
}
@@ -113,21 +150,21 @@ public class EntityDescriptorDescriptionConverter implements ClientDescriptionCo
String logoutRedirect = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
if (logoutRedirect != null) attributes.put(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, logoutRedirect);
- String assertionConsumerServicePostBinding = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
+ String assertionConsumerServicePostBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (assertionConsumerServicePostBinding != null) {
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, assertionConsumerServicePostBinding);
redirectUris.add(assertionConsumerServicePostBinding);
}
- String assertionConsumerServiceRedirectBinding = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
+ String assertionConsumerServiceRedirectBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
if (assertionConsumerServiceRedirectBinding != null) {
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, assertionConsumerServiceRedirectBinding);
redirectUris.add(assertionConsumerServiceRedirectBinding);
}
- String assertionConsumerServiceSoapBinding = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_SOAP_BINDING.get());
+ String assertionConsumerServiceSoapBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_SOAP_BINDING.get());
if (assertionConsumerServiceSoapBinding != null) {
redirectUris.add(assertionConsumerServiceSoapBinding);
}
- String assertionConsumerServicePaosBinding = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_PAOS_BINDING.get());
+ String assertionConsumerServicePaosBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_PAOS_BINDING.get());
if (assertionConsumerServicePaosBinding != null) {
redirectUris.add(assertionConsumerServicePaosBinding);
}