KEYCLOAK-4315 Remove some dead/duplicate classes
This commit is contained in:
parent
5d5373454c
commit
84ea3f8cb1
24 changed files with 203 additions and 1563 deletions
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<timestamp>${maven.build.timestamp}</timestamp>
|
<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>
|
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -56,7 +57,6 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.12</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -88,6 +88,35 @@
|
||||||
<target>${maven.compiler.target}</target>
|
<target>${maven.compiler.target}</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</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>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.saml.common.util;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.PropertyPermission;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Privileged Blocks
|
* Privileged Blocks
|
||||||
|
@ -28,6 +29,14 @@ import java.security.PrivilegedAction;
|
||||||
*/
|
*/
|
||||||
public class SecurityActions {
|
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
|
* <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>
|
* the specified {@link Class}, if not found it will try to load from using TCL. </p>
|
||||||
|
@ -37,11 +46,17 @@ public class SecurityActions {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
|
public static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
|
||||||
|
if (fullQualifiedName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
|
sm.checkPackageDefinition(extractPackageNameFromClassName(fullQualifiedName));
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
||||||
|
@Override
|
||||||
public Class<?> run() {
|
public Class<?> run() {
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
ClassLoader classLoader = theClass.getClassLoader();
|
||||||
|
|
||||||
|
@ -73,11 +88,17 @@ public class SecurityActions {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
|
public static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
|
||||||
|
if (fullQualifiedName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
|
sm.checkPackageDefinition(extractPackageNameFromClassName(fullQualifiedName));
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
||||||
|
@Override
|
||||||
public Class<?> run() {
|
public Class<?> run() {
|
||||||
try {
|
try {
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
return classLoader.loadClass(fullQualifiedName);
|
||||||
|
@ -103,13 +124,14 @@ public class SecurityActions {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static URL loadResource(final Class<?> clazz, final String resourceName) {
|
public static URL loadResource(final Class<?> clazz, final String resourceName) {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<URL>() {
|
return AccessController.doPrivileged(new PrivilegedAction<URL>() {
|
||||||
|
@Override
|
||||||
public URL run() {
|
public URL run() {
|
||||||
URL url = null;
|
URL url;
|
||||||
ClassLoader clazzLoader = clazz.getClassLoader();
|
ClassLoader clazzLoader = clazz.getClassLoader();
|
||||||
url = clazzLoader.getResource(resourceName);
|
url = clazzLoader.getResource(resourceName);
|
||||||
|
|
||||||
|
@ -122,7 +144,7 @@ public class SecurityActions {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
URL url = null;
|
URL url;
|
||||||
ClassLoader clazzLoader = clazz.getClassLoader();
|
ClassLoader clazzLoader = clazz.getClassLoader();
|
||||||
url = clazzLoader.getResource(resourceName);
|
url = clazzLoader.getResource(resourceName);
|
||||||
|
|
||||||
|
@ -143,11 +165,13 @@ public class SecurityActions {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static void setSystemProperty(final String key, final String value) {
|
public static void setSystemProperty(final String key, final String value) {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
|
sm.checkPermission(new PropertyPermission(key, "write"));
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
@Override
|
||||||
public Object run() {
|
public Object run() {
|
||||||
System.setProperty(key, value);
|
System.setProperty(key, value);
|
||||||
return null;
|
return null;
|
||||||
|
@ -167,11 +191,13 @@ public class SecurityActions {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static String getSystemProperty(final String key, final String defaultValue) {
|
public static String getSystemProperty(final String key, final String defaultValue) {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
|
sm.checkPermission(new PropertyPermission(key, "read"));
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||||
|
@Override
|
||||||
public String run() {
|
public String run() {
|
||||||
return System.getProperty(key, defaultValue);
|
return System.getProperty(key, defaultValue);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +214,9 @@ public class SecurityActions {
|
||||||
*/
|
*/
|
||||||
public static ClassLoader getTCCL() {
|
public static ClassLoader getTCCL() {
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
|
System.getSecurityManager().checkPermission(new RuntimePermission("getClassLoader"));
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
||||||
|
@Override
|
||||||
public ClassLoader run() {
|
public ClassLoader run() {
|
||||||
return Thread.currentThread().getContextClassLoader();
|
return Thread.currentThread().getContextClassLoader();
|
||||||
}
|
}
|
||||||
|
@ -205,7 +233,9 @@ public class SecurityActions {
|
||||||
*/
|
*/
|
||||||
public static void setTCCL(final ClassLoader paramCl) {
|
public static void setTCCL(final ClassLoader paramCl) {
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
|
System.getSecurityManager().checkPermission(new RuntimePermission("setContextClassLoader"));
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
|
@Override
|
||||||
public Void run() {
|
public Void run() {
|
||||||
Thread.currentThread().setContextClassLoader(paramCl);
|
Thread.currentThread().setContextClassLoader(paramCl);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class StaxUtil {
|
||||||
|
|
||||||
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
|
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
|
* Flush the stream writer
|
||||||
|
@ -341,10 +341,10 @@ public class StaxUtil {
|
||||||
writeStartElement(writer, domElementPrefix, domElement.getLocalName(), domElementNS);
|
writeStartElement(writer, domElementPrefix, domElement.getLocalName(), domElementNS);
|
||||||
|
|
||||||
// Should we register namespace
|
// Should we register namespace
|
||||||
if (domElementPrefix != "" && !registeredNSStack.get().contains(domElementNS)) {
|
if (! domElementPrefix.isEmpty() && !registeredNSStack.get().contains(domElementNS)) {
|
||||||
// writeNameSpace(writer, domElementPrefix, domElementNS );
|
// writeNameSpace(writer, domElementPrefix, domElementNS );
|
||||||
registeredNSStack.get().push(domElementNS);
|
registeredNSStack.get().push(domElementNS);
|
||||||
} else if (domElementPrefix == "" && domElementNS != null) {
|
} else if (domElementPrefix.isEmpty() && ! domElementNS.isEmpty()) {
|
||||||
writeNameSpace(writer, "xmlns", domElementNS);
|
writeNameSpace(writer, "xmlns", domElementNS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,55 +59,6 @@ public class StringUtil {
|
||||||
return str == null || str.isEmpty();
|
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}
|
* Match two strings else throw a {@link RuntimeException}
|
||||||
*
|
*
|
||||||
|
@ -118,67 +69,4 @@ public class StringUtil {
|
||||||
if (!first.equals(second))
|
if (!first.equals(second))
|
||||||
throw logger.notEqualError(first, 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};
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.core.parsers.util;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Privileged Blocks
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Oct 25, 2010
|
|
||||||
*/
|
|
||||||
public class SecurityActions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Returns a system property value using the specified <code>key</code>. If not found the
|
|
||||||
* <code>defaultValue</code> will be returned.</p>
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param defaultValue
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static String getSystemProperty(final String key, final String defaultValue) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
|
||||||
public String run() {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a resource based on the passed {@link Class} classloader. Failing which try with the Thread Context CL
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @param resourceName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static URL loadResource(final Class<?> clazz, final String resourceName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<URL>() {
|
|
||||||
public URL run() {
|
|
||||||
URL url = null;
|
|
||||||
ClassLoader clazzLoader = clazz.getClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
|
|
||||||
if (url == null) {
|
|
||||||
clazzLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
URL url = null;
|
|
||||||
ClassLoader clazzLoader = clazz.getClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
|
|
||||||
if (url == null) {
|
|
||||||
clazzLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.core.saml.v2.util;
|
|
||||||
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Privileged Blocks
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Dec 9, 2008
|
|
||||||
*/
|
|
||||||
class SecurityActions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <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>
|
|
||||||
*
|
|
||||||
* @param theClass
|
|
||||||
* @param fullQualifiedName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
|
||||||
public Class<?> run() {
|
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
|
||||||
|
|
||||||
Class<?> clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
if (clazz == null) {
|
|
||||||
classLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
|
||||||
|
|
||||||
Class<?> clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
if (clazz == null) {
|
|
||||||
classLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Loads a class from the specified {@link ClassLoader} using the <code>fullQualifiedName</code> supplied.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param classLoader
|
|
||||||
* @param fullQualifiedName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
|
||||||
public Class<?> run() {
|
|
||||||
try {
|
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Returns a system property value using the specified <code>key</code>. If not found the
|
|
||||||
* <code>defaultValue</code> will be returned.</p>
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param defaultValue
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static String getSystemProperty(final String key, final String defaultValue) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
|
||||||
public String run() {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Thread Context ClassLoader
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static ClassLoader getTCCL() {
|
|
||||||
if (System.getSecurityManager() != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
|
||||||
public ClassLoader run() {
|
|
||||||
return Thread.currentThread().getContextClassLoader();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Thread.currentThread().getContextClassLoader();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Thread Context ClassLoader
|
|
||||||
*
|
|
||||||
* @param paramCl
|
|
||||||
*/
|
|
||||||
static void setTCCL(final ClassLoader paramCl) {
|
|
||||||
if (System.getSecurityManager() != null) {
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
|
||||||
public Void run() {
|
|
||||||
Thread.currentThread().setContextClassLoader(paramCl);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Thread.currentThread().setContextClassLoader(paramCl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
||||||
|
|
||||||
import javax.xml.datatype.DatatypeConfigurationException;
|
import javax.xml.datatype.DatatypeConfigurationException;
|
||||||
|
|
|
@ -1,208 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.core.util;
|
|
||||||
|
|
||||||
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.EDTChoiceType;
|
|
||||||
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType.EDTDescriptorChoiceType;
|
|
||||||
import org.keycloak.dom.saml.v2.metadata.IDPSSODescriptorType;
|
|
||||||
import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
|
|
||||||
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
|
|
||||||
import org.keycloak.saml.common.PicketLinkLogger;
|
|
||||||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility for configuration
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Nov 13, 2009
|
|
||||||
*/
|
|
||||||
public class CoreConfigUtil {
|
|
||||||
|
|
||||||
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the first metadata descriptor for an IDP
|
|
||||||
*
|
|
||||||
* @param entitiesDescriptor
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static IDPSSODescriptorType getIDPDescriptor(EntitiesDescriptorType entitiesDescriptor) {
|
|
||||||
IDPSSODescriptorType idp = null;
|
|
||||||
List<Object> entitiesList = entitiesDescriptor.getEntityDescriptor();
|
|
||||||
for (Object theObject : entitiesList) {
|
|
||||||
if (theObject instanceof EntitiesDescriptorType) {
|
|
||||||
idp = getIDPDescriptor((EntitiesDescriptorType) theObject);
|
|
||||||
} else if (theObject instanceof EntityDescriptorType) {
|
|
||||||
idp = getIDPDescriptor((EntityDescriptorType) theObject);
|
|
||||||
}
|
|
||||||
if (idp != null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the IDP metadata descriptor from an entity descriptor
|
|
||||||
*
|
|
||||||
* @param entityDescriptor
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static IDPSSODescriptorType getIDPDescriptor(EntityDescriptorType entityDescriptor) {
|
|
||||||
List<EDTChoiceType> edtChoices = entityDescriptor.getChoiceType();
|
|
||||||
for (EDTChoiceType edt : edtChoices) {
|
|
||||||
List<EDTDescriptorChoiceType> edtDescriptors = edt.getDescriptors();
|
|
||||||
for (EDTDescriptorChoiceType edtDesc : edtDescriptors) {
|
|
||||||
IDPSSODescriptorType idpSSO = edtDesc.getIdpDescriptor();
|
|
||||||
if (idpSSO != null) {
|
|
||||||
return idpSSO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the SP Descriptor from an entity descriptor
|
|
||||||
*
|
|
||||||
* @param entityDescriptor
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static SPSSODescriptorType getSPDescriptor(EntityDescriptorType entityDescriptor) {
|
|
||||||
List<EDTChoiceType> edtChoices = entityDescriptor.getChoiceType();
|
|
||||||
for (EDTChoiceType edt : edtChoices) {
|
|
||||||
List<EDTDescriptorChoiceType> edtDescriptors = edt.getDescriptors();
|
|
||||||
for (EDTDescriptorChoiceType edtDesc : edtDescriptors) {
|
|
||||||
SPSSODescriptorType spSSO = edtDesc.getSpDescriptor();
|
|
||||||
if (spSSO != null) {
|
|
||||||
return spSSO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a binding uri, get the IDP identity url
|
|
||||||
*
|
|
||||||
* @param idp
|
|
||||||
* @param bindingURI
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getIdentityURL(IDPSSODescriptorType idp, String bindingURI) {
|
|
||||||
String identityURL = null;
|
|
||||||
|
|
||||||
List<EndpointType> endpoints = idp.getSingleSignOnService();
|
|
||||||
for (EndpointType endpoint : endpoints) {
|
|
||||||
if (endpoint.getBinding().toString().equals(bindingURI)) {
|
|
||||||
identityURL = endpoint.getLocation().toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return identityURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a binding uri, get the IDP identity url
|
|
||||||
*
|
|
||||||
* @param idp
|
|
||||||
* @param bindingURI
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getLogoutURL(IDPSSODescriptorType idp, String bindingURI) {
|
|
||||||
String logoutURL = null;
|
|
||||||
|
|
||||||
List<EndpointType> endpoints = idp.getSingleLogoutService();
|
|
||||||
for (EndpointType endpoint : endpoints) {
|
|
||||||
if (endpoint.getBinding().toString().equals(bindingURI)) {
|
|
||||||
logoutURL = endpoint.getLocation().toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return logoutURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a binding uri, get the IDP logout response url (used for global logouts)
|
|
||||||
*/
|
|
||||||
public static String getLogoutResponseLocation(IDPSSODescriptorType idp, String bindingURI) {
|
|
||||||
String logoutResponseLocation = null;
|
|
||||||
|
|
||||||
List<EndpointType> endpoints = idp.getSingleLogoutService();
|
|
||||||
for (EndpointType endpoint : endpoints) {
|
|
||||||
if (endpoint.getBinding().toString().equals(bindingURI)) {
|
|
||||||
if (endpoint.getResponseLocation() != null) {
|
|
||||||
logoutResponseLocation = endpoint.getResponseLocation().toString();
|
|
||||||
} else {
|
|
||||||
logoutResponseLocation = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return logoutResponseLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the service url for the SP
|
|
||||||
*
|
|
||||||
* @param sp
|
|
||||||
* @param bindingURI
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getServiceURL(SPSSODescriptorType sp, String bindingURI) {
|
|
||||||
String serviceURL = null;
|
|
||||||
|
|
||||||
List<IndexedEndpointType> endpoints = sp.getAssertionConsumerService();
|
|
||||||
for (IndexedEndpointType endpoint : endpoints) {
|
|
||||||
if (endpoint.getBinding().toString().equals(bindingURI)) {
|
|
||||||
serviceURL = endpoint.getLocation().toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return serviceURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addAllEntityDescriptorsRecursively(List<EntityDescriptorType> resultList,
|
|
||||||
EntitiesDescriptorType entitiesDescriptorType) {
|
|
||||||
List<Object> entities = entitiesDescriptorType.getEntityDescriptor();
|
|
||||||
for (Object o : entities) {
|
|
||||||
if (o instanceof EntitiesDescriptorType) {
|
|
||||||
addAllEntityDescriptorsRecursively(resultList, (EntitiesDescriptorType) o);
|
|
||||||
} else if (o instanceof EntityDescriptorType) {
|
|
||||||
resultList.add((EntityDescriptorType) o);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Wrong type: " + o.getClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.core.util;
|
|
||||||
|
|
||||||
import javax.crypto.KeyGenerator;
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility to generate symmetric key
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Feb 4, 2009
|
|
||||||
*/
|
|
||||||
public class EncryptionKeyUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a secret key useful for encryption/decryption
|
|
||||||
*
|
|
||||||
* @param encAlgo
|
|
||||||
* @param keySize Length of the key (if 0, defaults to 128 bits)
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
*/
|
|
||||||
public static SecretKey getSecretKey(String encAlgo, int keySize) throws GeneralSecurityException {
|
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(encAlgo);
|
|
||||||
if (keySize == 0)
|
|
||||||
keySize = 128;
|
|
||||||
keyGenerator.init(keySize);
|
|
||||||
return keyGenerator.generateKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.processing.core.util;
|
package org.keycloak.saml.processing.core.util;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.keycloak.saml.common.PicketLinkLogger;
|
||||||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import org.xml.sax.ErrorHandler;
|
import org.xml.sax.ErrorHandler;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.SAXParseException;
|
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";
|
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 {
|
static {
|
||||||
// Useful on Sun VMs. Harmless on other VMs.
|
// Useful on Sun VMs. Harmless on other VMs.
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.common.util.DocumentUtil;
|
import org.keycloak.saml.common.util.DocumentUtil;
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.xml.sax.ErrorHandler;
|
import org.xml.sax.ErrorHandler;
|
||||||
|
|
|
@ -1,184 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.core.util;
|
|
||||||
|
|
||||||
import org.keycloak.saml.common.PicketLinkLogger;
|
|
||||||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.Key;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility to handle Java Keystore
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Jan 12, 2009
|
|
||||||
*/
|
|
||||||
public class KeyStoreUtil {
|
|
||||||
|
|
||||||
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the KeyStore
|
|
||||||
*
|
|
||||||
* @param keyStoreFile
|
|
||||||
* @param storePass
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static KeyStore getKeyStore(File keyStoreFile, char[] storePass) throws GeneralSecurityException, IOException {
|
|
||||||
FileInputStream fis = new FileInputStream(keyStoreFile);
|
|
||||||
return getKeyStore(fis, storePass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Keystore given the url to the keystore file as a string
|
|
||||||
*
|
|
||||||
* @param fileURL
|
|
||||||
* @param storePass
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static KeyStore getKeyStore(String fileURL, char[] storePass) throws GeneralSecurityException, IOException {
|
|
||||||
if (fileURL == null)
|
|
||||||
throw logger.nullArgumentError("fileURL");
|
|
||||||
|
|
||||||
File file = new File(fileURL);
|
|
||||||
FileInputStream fis = new FileInputStream(file);
|
|
||||||
return getKeyStore(fis, storePass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Keystore given the URL to the keystore
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* @param storePass
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static KeyStore getKeyStore(URL url, char[] storePass) throws GeneralSecurityException, IOException {
|
|
||||||
if (url == null)
|
|
||||||
throw logger.nullArgumentError("url");
|
|
||||||
|
|
||||||
return getKeyStore(url.openStream(), storePass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Key Store <b>Note:</b> This method wants the InputStream to be not null.
|
|
||||||
*
|
|
||||||
* @param ksStream
|
|
||||||
* @param storePass
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
* @throws IllegalArgumentException if ksStream is null
|
|
||||||
*/
|
|
||||||
public static KeyStore getKeyStore(InputStream ksStream, char[] storePass) throws GeneralSecurityException, IOException {
|
|
||||||
if (ksStream == null)
|
|
||||||
throw logger.nullArgumentError("InputStream for the KeyStore");
|
|
||||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
|
||||||
ks.load(ksStream, storePass);
|
|
||||||
return ks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Public Key from the keystore
|
|
||||||
*
|
|
||||||
* @param ks
|
|
||||||
* @param alias
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
*/
|
|
||||||
public static PublicKey getPublicKey(KeyStore ks, String alias, char[] password) throws GeneralSecurityException {
|
|
||||||
PublicKey publicKey = null;
|
|
||||||
|
|
||||||
// Get private key
|
|
||||||
Key key = ks.getKey(alias, password);
|
|
||||||
if (key instanceof PrivateKey) {
|
|
||||||
// Get certificate of public key
|
|
||||||
Certificate cert = ks.getCertificate(alias);
|
|
||||||
|
|
||||||
// Get public key
|
|
||||||
publicKey = cert.getPublicKey();
|
|
||||||
}
|
|
||||||
// if alias is a certificate alias, get the public key from the certificate.
|
|
||||||
if (publicKey == null) {
|
|
||||||
Certificate cert = ks.getCertificate(alias);
|
|
||||||
if (cert != null)
|
|
||||||
publicKey = cert.getPublicKey();
|
|
||||||
}
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a certificate to the KeyStore
|
|
||||||
*
|
|
||||||
* @param keystoreFile
|
|
||||||
* @param storePass
|
|
||||||
* @param alias
|
|
||||||
* @param cert
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static void addCertificate(File keystoreFile, char[] storePass, String alias, Certificate cert)
|
|
||||||
throws GeneralSecurityException, IOException {
|
|
||||||
KeyStore keystore = getKeyStore(keystoreFile, storePass);
|
|
||||||
|
|
||||||
// Add the certificate
|
|
||||||
keystore.setCertificateEntry(alias, cert);
|
|
||||||
|
|
||||||
// Save the new keystore contents
|
|
||||||
FileOutputStream out = null;
|
|
||||||
try {
|
|
||||||
out = new FileOutputStream(keystoreFile);
|
|
||||||
keystore.store(out, storePass);
|
|
||||||
} finally {
|
|
||||||
if (out != null) {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.saml.processing.core.util;
|
||||||
import org.keycloak.saml.common.PicketLinkLogger;
|
import org.keycloak.saml.common.PicketLinkLogger;
|
||||||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
|
|
|
@ -1,224 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.core.util;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Privileged Blocks
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Dec 9, 2008
|
|
||||||
*/
|
|
||||||
class SecurityActions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <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>
|
|
||||||
*
|
|
||||||
* @param theClass
|
|
||||||
* @param fullQualifiedName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
|
||||||
public Class<?> run() {
|
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
|
||||||
|
|
||||||
Class<?> clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
if (clazz == null) {
|
|
||||||
classLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
|
||||||
|
|
||||||
Class<?> clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
if (clazz == null) {
|
|
||||||
classLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Loads a class from the specified {@link ClassLoader} using the <code>fullQualifiedName</code> supplied.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param classLoader
|
|
||||||
* @param fullQualifiedName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
|
||||||
public Class<?> run() {
|
|
||||||
try {
|
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a resource based on the passed {@link Class} classloader. Failing which try with the Thread Context CL
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @param resourceName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static URL loadResource(final Class<?> clazz, final String resourceName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<URL>() {
|
|
||||||
public URL run() {
|
|
||||||
URL url = null;
|
|
||||||
ClassLoader clazzLoader = clazz.getClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
|
|
||||||
if (url == null) {
|
|
||||||
clazzLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
URL url = null;
|
|
||||||
ClassLoader clazzLoader = clazz.getClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
|
|
||||||
if (url == null) {
|
|
||||||
clazzLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
url = clazzLoader.getResource(resourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the system property
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param defaultValue
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static void setSystemProperty(final String key, final String value) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
|
||||||
public Object run() {
|
|
||||||
System.setProperty(key, value);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
System.setProperty(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Returns a system property value using the specified <code>key</code>. If not found the
|
|
||||||
* <code>defaultValue</code> will be returned.</p>
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param defaultValue
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static String getSystemProperty(final String key, final String defaultValue) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
|
||||||
public String run() {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Thread Context ClassLoader
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static ClassLoader getTCCL() {
|
|
||||||
if (System.getSecurityManager() != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
|
||||||
public ClassLoader run() {
|
|
||||||
return Thread.currentThread().getContextClassLoader();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Thread.currentThread().getContextClassLoader();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Thread Context ClassLoader
|
|
||||||
*
|
|
||||||
* @param paramCl
|
|
||||||
*/
|
|
||||||
static void setTCCL(final ClassLoader paramCl) {
|
|
||||||
if (System.getSecurityManager() != null) {
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
|
||||||
public Void run() {
|
|
||||||
Thread.currentThread().setContextClassLoader(paramCl);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Thread.currentThread().setContextClassLoader(paramCl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -88,6 +88,7 @@ import javax.xml.crypto.KeySelectorResult;
|
||||||
import javax.xml.crypto.XMLCryptoContext;
|
import javax.xml.crypto.XMLCryptoContext;
|
||||||
import javax.xml.crypto.dsig.keyinfo.KeyName;
|
import javax.xml.crypto.dsig.keyinfo.KeyName;
|
||||||
import org.keycloak.rotation.KeyLocator;
|
import org.keycloak.rotation.KeyLocator;
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import org.keycloak.saml.processing.api.util.KeyInfoTools;
|
import org.keycloak.saml.processing.api.util.KeyInfoTools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,344 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.web.util;
|
|
||||||
|
|
||||||
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
|
||||||
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
|
||||||
import org.keycloak.saml.common.PicketLinkLogger;
|
|
||||||
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.exceptions.ProcessingException;
|
|
||||||
import org.keycloak.saml.common.util.DocumentUtil;
|
|
||||||
import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
|
|
||||||
import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
|
|
||||||
import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
import static org.keycloak.saml.common.util.StringUtil.isNotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signature Support for the HTTP/Redirect binding
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Dec 16, 2008
|
|
||||||
*/
|
|
||||||
public class RedirectBindingSignatureUtil {
|
|
||||||
|
|
||||||
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the URL for the SAML request that contains the signature and signature algorithm
|
|
||||||
*
|
|
||||||
* @param authRequest
|
|
||||||
* @param relayState
|
|
||||||
* @param signingKey
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws SAXException
|
|
||||||
* @throws IOException
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
*/
|
|
||||||
public static String getSAMLRequestURLWithSignature(AuthnRequestType authRequest, String relayState, PrivateKey signingKey)
|
|
||||||
throws SAXException, IOException, GeneralSecurityException {
|
|
||||||
SAML2Request saml2Request = new SAML2Request();
|
|
||||||
|
|
||||||
// Deal with the original request
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
|
|
||||||
saml2Request.marshall(authRequest, sw);
|
|
||||||
|
|
||||||
// URL Encode the Request
|
|
||||||
String urlEncodedRequest = RedirectBindingUtil.deflateBase64URLEncode(sw.toString());
|
|
||||||
|
|
||||||
String urlEncodedRelayState = null;
|
|
||||||
|
|
||||||
if (isNotNull(relayState))
|
|
||||||
urlEncodedRelayState = URLEncoder.encode(relayState, GeneralConstants.SAML_CHARSET_NAME);
|
|
||||||
|
|
||||||
byte[] sigValue = computeSignature(GeneralConstants.SAML_REQUEST_KEY, urlEncodedRequest, urlEncodedRelayState,
|
|
||||||
signingKey);
|
|
||||||
|
|
||||||
// Now construct the URL
|
|
||||||
return getRequestRedirectURLWithSignature(urlEncodedRequest, urlEncodedRelayState, sigValue, signingKey.getAlgorithm());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the URL for the SAML request that contains the signature and signature algorithm
|
|
||||||
*
|
|
||||||
* @param responseType
|
|
||||||
* @param relayState
|
|
||||||
* @param signingKey
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
*/
|
|
||||||
public static String getSAMLResponseURLWithSignature(ResponseType responseType, String relayState, PrivateKey signingKey)
|
|
||||||
throws IOException, GeneralSecurityException {
|
|
||||||
SAML2Response saml2Response = new SAML2Response();
|
|
||||||
|
|
||||||
Document responseDoc = saml2Response.convert(responseType);
|
|
||||||
|
|
||||||
// URL Encode the Request
|
|
||||||
String responseString = DocumentUtil.getDocumentAsString(responseDoc);
|
|
||||||
|
|
||||||
String urlEncodedResponse = RedirectBindingUtil.deflateBase64URLEncode(responseString);
|
|
||||||
|
|
||||||
String urlEncodedRelayState = null;
|
|
||||||
if (isNotNull(relayState))
|
|
||||||
urlEncodedRelayState = URLEncoder.encode(relayState, GeneralConstants.SAML_CHARSET_NAME);
|
|
||||||
|
|
||||||
byte[] sigValue = computeSignature(GeneralConstants.SAML_RESPONSE_KEY, urlEncodedResponse, urlEncodedRelayState,
|
|
||||||
signingKey);
|
|
||||||
|
|
||||||
// Now construct the URL
|
|
||||||
return getResponseRedirectURLWithSignature(urlEncodedResponse, urlEncodedRelayState, sigValue,
|
|
||||||
signingKey.getAlgorithm());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an url-encoded saml request and relay state and a private key, compute the url
|
|
||||||
*
|
|
||||||
* @param urlEncodedRequest
|
|
||||||
* @param urlEncodedRelayState
|
|
||||||
* @param signingKey
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static String getSAMLRequestURLWithSignature(String urlEncodedRequest, String urlEncodedRelayState,
|
|
||||||
PrivateKey signingKey) throws IOException, GeneralSecurityException {
|
|
||||||
byte[] sigValue = computeSignature(GeneralConstants.SAML_REQUEST_KEY, urlEncodedRequest, urlEncodedRelayState,
|
|
||||||
signingKey);
|
|
||||||
return getRequestRedirectURLWithSignature(urlEncodedRequest, urlEncodedRelayState, sigValue, signingKey.getAlgorithm());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an url-encoded saml response and relay state and a private key, compute the url
|
|
||||||
*
|
|
||||||
* @param urlEncodedResponse
|
|
||||||
* @param urlEncodedRelayState
|
|
||||||
* @param signingKey
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static String getSAMLResponseURLWithSignature(String urlEncodedResponse, String urlEncodedRelayState,
|
|
||||||
PrivateKey signingKey) throws IOException, GeneralSecurityException {
|
|
||||||
byte[] sigValue = computeSignature(GeneralConstants.SAML_RESPONSE_KEY, urlEncodedResponse, urlEncodedRelayState,
|
|
||||||
signingKey);
|
|
||||||
return getResponseRedirectURLWithSignature(urlEncodedResponse, urlEncodedRelayState, sigValue,
|
|
||||||
signingKey.getAlgorithm());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From the SAML Request URL, get the Request object
|
|
||||||
*
|
|
||||||
* @param signedURL
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws ParsingException
|
|
||||||
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
|
||||||
* @throws ConfigurationException
|
|
||||||
*/
|
|
||||||
public static AuthnRequestType getRequestFromSignedURL(String signedURL) throws ConfigurationException,
|
|
||||||
ProcessingException, ParsingException, IOException {
|
|
||||||
String samlRequestTokenValue = getTokenValue(signedURL, GeneralConstants.SAML_REQUEST_KEY);
|
|
||||||
|
|
||||||
SAML2Request saml2Request = new SAML2Request();
|
|
||||||
return saml2Request.getAuthnRequestType(RedirectBindingUtil.urlBase64DeflateDecode(samlRequestTokenValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the signature value from the url
|
|
||||||
*
|
|
||||||
* @param signedURL
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static byte[] getSignatureValueFromSignedURL(String signedURL) throws IOException {
|
|
||||||
String sigValueTokenValue = getTokenValue(signedURL, GeneralConstants.SAML_SIGNATURE_REQUEST_KEY);
|
|
||||||
if (sigValueTokenValue == null)
|
|
||||||
throw new IllegalStateException(logger.samlHandlerSignatureNotPresentError());
|
|
||||||
return RedirectBindingUtil.urlBase64Decode(sigValueTokenValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From the query string that contains key/value pairs, get the value of a key <b>Note:</b> if the token is null, a
|
|
||||||
* null
|
|
||||||
* value is returned
|
|
||||||
*
|
|
||||||
* @param queryString
|
|
||||||
* @param token
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getTokenValue(String queryString, String token) {
|
|
||||||
return getTokenValue(getToken(queryString, token));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean validateSignature(String queryString, PublicKey validatingKey, byte[] sigValue)
|
|
||||||
throws UnsupportedEncodingException, GeneralSecurityException {
|
|
||||||
// Construct the url again
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
if (isRequestQueryString(queryString)) {
|
|
||||||
addParameter(sb, GeneralConstants.SAML_REQUEST_KEY,
|
|
||||||
RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.SAML_REQUEST_KEY));
|
|
||||||
} else {
|
|
||||||
addParameter(sb, GeneralConstants.SAML_RESPONSE_KEY,
|
|
||||||
RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.SAML_RESPONSE_KEY));
|
|
||||||
}
|
|
||||||
|
|
||||||
String relayStateFromURL = RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.RELAY_STATE);
|
|
||||||
|
|
||||||
if (isNotNull(relayStateFromURL)) {
|
|
||||||
addParameter(sb, GeneralConstants.RELAY_STATE, relayStateFromURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY,
|
|
||||||
RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY));
|
|
||||||
|
|
||||||
return SignatureUtil.validate(sb.toString().getBytes(GeneralConstants.SAML_CHARSET), sigValue, validatingKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isRequestQueryString(String queryString) {
|
|
||||||
return RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.SAML_REQUEST_KEY) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ***************** Private Methods **************
|
|
||||||
|
|
||||||
private static byte[] computeSignature(String samlParameter, String urlEncoded, String urlEncodedRelayState,
|
|
||||||
PrivateKey signingKey) throws IOException, GeneralSecurityException {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
addParameter(sb, samlParameter, urlEncoded);
|
|
||||||
|
|
||||||
if (isNotNull(urlEncodedRelayState)) {
|
|
||||||
addParameter(sb, GeneralConstants.RELAY_STATE, urlEncodedRelayState);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SigAlg
|
|
||||||
String algo = signingKey.getAlgorithm();
|
|
||||||
String sigAlg = SignatureUtil.getXMLSignatureAlgorithmURI(algo);
|
|
||||||
|
|
||||||
sigAlg = URLEncoder.encode(sigAlg, GeneralConstants.SAML_CHARSET_NAME);
|
|
||||||
|
|
||||||
addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, sigAlg);
|
|
||||||
|
|
||||||
byte[] sigValue = SignatureUtil.sign(sb.toString(), signingKey);
|
|
||||||
|
|
||||||
return sigValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getRequestRedirectURLWithSignature(String urlEncodedRequest, String urlEncodedRelayState,
|
|
||||||
byte[] signature, String sigAlgo) throws IOException {
|
|
||||||
return getRedirectURLWithSignature(GeneralConstants.SAML_REQUEST_KEY, urlEncodedRequest, urlEncodedRelayState,
|
|
||||||
signature, sigAlgo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getResponseRedirectURLWithSignature(String urlEncodedResponse, String urlEncodedRelayState,
|
|
||||||
byte[] signature, String sigAlgo) throws IOException {
|
|
||||||
return getRedirectURLWithSignature(GeneralConstants.SAML_RESPONSE_KEY, urlEncodedResponse, urlEncodedRelayState,
|
|
||||||
signature, sigAlgo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getRedirectURLWithSignature(String samlParameter, String urlEncoded, String urlEncodedRelayState,
|
|
||||||
byte[] signature, String sigAlgo) throws IOException {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
addParameter(sb, samlParameter, urlEncoded);
|
|
||||||
|
|
||||||
if (isNotNull(urlEncodedRelayState)) {
|
|
||||||
addParameter(sb, GeneralConstants.RELAY_STATE, urlEncodedRelayState);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SigAlg
|
|
||||||
String sigAlg = SignatureUtil.getXMLSignatureAlgorithmURI(sigAlgo);
|
|
||||||
|
|
||||||
sigAlg = URLEncoder.encode(sigAlg, GeneralConstants.SAML_CHARSET_NAME);
|
|
||||||
|
|
||||||
addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, sigAlg);
|
|
||||||
|
|
||||||
// Encode the signature value
|
|
||||||
String encodedSig = RedirectBindingUtil.base64URLEncode(signature);
|
|
||||||
|
|
||||||
addParameter(sb, GeneralConstants.SAML_SIGNATURE_REQUEST_KEY, encodedSig);
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addParameter(StringBuilder queryString, String paramName, String paramValue) {
|
|
||||||
String parameterSeparator = "&";
|
|
||||||
|
|
||||||
if (queryString.length() == 0) {
|
|
||||||
parameterSeparator = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
queryString.append(parameterSeparator).append(paramName).append("=").append(paramValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getToken(String queryString, String token) {
|
|
||||||
if (queryString == null)
|
|
||||||
throw logger.nullArgumentError("queryString");
|
|
||||||
|
|
||||||
token += "=";
|
|
||||||
|
|
||||||
int start = queryString.indexOf(token);
|
|
||||||
if (start < 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int end = queryString.indexOf("&", start);
|
|
||||||
|
|
||||||
if (end == -1)
|
|
||||||
return queryString.substring(start);
|
|
||||||
|
|
||||||
return queryString.substring(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getTokenValue(String token) {
|
|
||||||
if (token == null)
|
|
||||||
return token;
|
|
||||||
|
|
||||||
int eq = token.indexOf('=');
|
|
||||||
if (eq == -1)
|
|
||||||
return token;
|
|
||||||
else
|
|
||||||
return token.substring(eq + 1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.processing.web.util;
|
|
||||||
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Privileged Blocks
|
|
||||||
*
|
|
||||||
* @author Anil.Saldhana@redhat.com
|
|
||||||
* @since Dec 9, 2008
|
|
||||||
*/
|
|
||||||
class SecurityActions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <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>
|
|
||||||
*
|
|
||||||
* @param theClass
|
|
||||||
* @param fullQualifiedName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static Class<?> loadClass(final Class<?> theClass, final String fullQualifiedName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
|
||||||
public Class<?> run() {
|
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
|
||||||
|
|
||||||
Class<?> clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
if (clazz == null) {
|
|
||||||
classLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ClassLoader classLoader = theClass.getClassLoader();
|
|
||||||
|
|
||||||
Class<?> clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
if (clazz == null) {
|
|
||||||
classLoader = Thread.currentThread().getContextClassLoader();
|
|
||||||
clazz = loadClass(classLoader, fullQualifiedName);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Loads a class from the specified {@link ClassLoader} using the <code>fullQualifiedName</code> supplied.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param classLoader
|
|
||||||
* @param fullQualifiedName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static Class<?> loadClass(final ClassLoader classLoader, final String fullQualifiedName) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
|
||||||
public Class<?> run() {
|
|
||||||
try {
|
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return classLoader.loadClass(fullQualifiedName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Returns a system property value using the specified <code>key</code>. If not found the
|
|
||||||
* <code>defaultValue</code> will be returned.</p>
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param defaultValue
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static String getSystemProperty(final String key, final String defaultValue) {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
|
|
||||||
if (sm != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
|
||||||
public String run() {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return System.getProperty(key, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.keycloak.saml.common.util;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author hmlnarik
|
|
||||||
*/
|
|
||||||
public class StringUtilTest {
|
|
||||||
|
|
||||||
public StringUtilTest() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetSystemPropertyAsString() {
|
|
||||||
System.setProperty("StringUtilTest.prop1", "value1");
|
|
||||||
System.setProperty("StringUtilTest.prop2", "value2");
|
|
||||||
|
|
||||||
assertThat(StringUtil.getSystemPropertyAsString("a"), is("a"));
|
|
||||||
assertThat(StringUtil.getSystemPropertyAsString("a ${StringUtilTest.prop1}"), is("a value1"));
|
|
||||||
assertThat(
|
|
||||||
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1"),
|
|
||||||
is("a" + "value1" + "StringUtilTest.prop1")
|
|
||||||
);
|
|
||||||
assertThat(
|
|
||||||
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1" + "${StringUtilTest.prop2}"),
|
|
||||||
is("a" + "value1" + "StringUtilTest.prop1" + "value2")
|
|
||||||
);
|
|
||||||
assertThat(
|
|
||||||
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1" + "${StringUtilTest.prop2}" + "${StringUtilTest.prop3::abc}"),
|
|
||||||
is("a" + "value1" + "StringUtilTest.prop1" + "value2" + "abc")
|
|
||||||
);
|
|
||||||
assertThat(
|
|
||||||
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1" + "${StringUtilTest.prop2}" + "${StringUtilTest.prop3::abc}" + "end"),
|
|
||||||
is("a" + "value1" + "StringUtilTest.prop1" + "value2" + "abc" + "end")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.processing.core.util;
|
package org.keycloak.saml.processing.core.util;
|
||||||
|
|
||||||
|
import org.keycloak.saml.common.util.SecurityActions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
3
saml-core/src/test/resources/all-permissions.policy
Normal file
3
saml-core/src/test/resources/all-permissions.policy
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
grant {
|
||||||
|
permission java.security.AllPermission;
|
||||||
|
};
|
15
saml-core/src/test/resources/named-permissions.policy
Normal file
15
saml-core/src/test/resources/named-permissions.policy
Normal file
|
@ -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";
|
||||||
|
};
|
|
@ -21,6 +21,8 @@ import org.keycloak.Config;
|
||||||
import org.keycloak.dom.saml.v2.metadata.EndpointType;
|
import org.keycloak.dom.saml.v2.metadata.EndpointType;
|
||||||
import org.keycloak.dom.saml.v2.metadata.EntitiesDescriptorType;
|
import org.keycloak.dom.saml.v2.metadata.EntitiesDescriptorType;
|
||||||
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
|
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.KeyDescriptorType;
|
||||||
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
|
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
|
||||||
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
|
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.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
|
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.saml.v2.util.SAMLMetadataUtil;
|
||||||
import org.keycloak.saml.processing.core.util.CoreConfigUtil;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -46,6 +47,7 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @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()));
|
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) {
|
private static ClientRepresentation loadEntityDescriptors(InputStream is) {
|
||||||
Object metadata;
|
Object metadata;
|
||||||
try {
|
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_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_SIGNATURE_ALGORITHM, SignatureAlgorithm.RSA_SHA256.toString());
|
||||||
attributes.put(SamlConfigAttributes.SAML_AUTHNSTATEMENT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
attributes.put(SamlConfigAttributes.SAML_AUTHNSTATEMENT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
||||||
SPSSODescriptorType spDescriptorType = CoreConfigUtil.getSPDescriptor(entity);
|
SPSSODescriptorType spDescriptorType = getSPDescriptor(entity);
|
||||||
if (spDescriptorType.isWantAssertionsSigned()) {
|
if (spDescriptorType.isWantAssertionsSigned()) {
|
||||||
attributes.put(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
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());
|
String logoutRedirect = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
|
||||||
if (logoutRedirect != null) attributes.put(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, logoutRedirect);
|
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) {
|
if (assertionConsumerServicePostBinding != null) {
|
||||||
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, assertionConsumerServicePostBinding);
|
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, assertionConsumerServicePostBinding);
|
||||||
redirectUris.add(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) {
|
if (assertionConsumerServiceRedirectBinding != null) {
|
||||||
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, assertionConsumerServiceRedirectBinding);
|
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, assertionConsumerServiceRedirectBinding);
|
||||||
redirectUris.add(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) {
|
if (assertionConsumerServiceSoapBinding != null) {
|
||||||
redirectUris.add(assertionConsumerServiceSoapBinding);
|
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) {
|
if (assertionConsumerServicePaosBinding != null) {
|
||||||
redirectUris.add(assertionConsumerServicePaosBinding);
|
redirectUris.add(assertionConsumerServicePaosBinding);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue