From 4f90ef67f698dfb45df0d2f4981271a7c8b47f04 Mon Sep 17 00:00:00 2001 From: Ricardo Martin Date: Tue, 17 Feb 2026 19:40:11 +0100 Subject: [PATCH] Limit the inflating size for the SAML redirect binding Closes #46372 Signed-off-by: rmartinc --- .../AbstractSamlAuthenticationHandler.java | 7 +- .../topics/templates/document-attributes.adoc | 1 + .../topics/changes/changes-26_5_4.adoc | 12 +++ .../org/keycloak/saml/SAMLRequestParser.java | 64 +++++-------- .../saml/processing/api/util/DeflateUtil.java | 94 ++++++++++++++++++- .../web/util/RedirectBindingUtil.java | 32 ++++++- .../keycloak/broker/saml/SAMLEndpoint.java | 14 ++- .../protocol/saml/SamlProtocolFactory.java | 27 +++++- .../keycloak/protocol/saml/SamlService.java | 12 ++- .../profile/ecp/SamlEcpProfileService.java | 4 +- .../test/broker/saml/SAMLParsingTest.java | 18 ++++ 11 files changed, 230 insertions(+), 55 deletions(-) diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java index 41818cc0e0b..dd8bca3e0ce 100644 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java @@ -76,6 +76,7 @@ import org.keycloak.saml.common.exceptions.ConfigurationException; import org.keycloak.saml.common.exceptions.ProcessingException; import org.keycloak.saml.common.util.DocumentUtil; import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature; +import org.keycloak.saml.processing.api.util.DeflateUtil; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil; import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator; @@ -100,6 +101,8 @@ import static org.keycloak.adapters.saml.SamlPrincipal.DEFAULT_ROLE_ATTRIBUTE_NA */ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthenticationHandler { + public static final String MAX_INFLAFING_SIZE_PROP = "org.keycloak.adapters.saml.maxInflatingSize"; + private static final long MAX_INFLAFING_SIZE = Long.getLong(MAX_INFLAFING_SIZE_PROP, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); protected static Logger log = Logger.getLogger(WebBrowserSsoAuthenticationHandler.class); protected final HttpFacade facade; @@ -177,7 +180,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic if (index > -1) { requestUri = requestUri.substring(0, index); } - holder = SAMLRequestParser.parseRequestRedirectBinding(samlRequest); + holder = SAMLRequestParser.parseRequestRedirectBinding(samlRequest, MAX_INFLAFING_SIZE); } else { postBinding = true; holder = SAMLRequestParser.parseRequestPostBinding(samlRequest); @@ -634,7 +637,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic } protected SAMLDocumentHolder extractRedirectBindingResponse(String response) { - return SAMLRequestParser.parseRequestRedirectBinding(response); + return SAMLRequestParser.parseRequestRedirectBinding(response, MAX_INFLAFING_SIZE); } diff --git a/docs/documentation/topics/templates/document-attributes.adoc b/docs/documentation/topics/templates/document-attributes.adoc index 816876b0924..915a347bdd4 100644 --- a/docs/documentation/topics/templates/document-attributes.adoc +++ b/docs/documentation/topics/templates/document-attributes.adoc @@ -99,6 +99,7 @@ :upgradingguide_link: {project_doc_base_url}/upgrading/ :upgradingguide_link_latest: {project_doc_base_url_latest}/upgrading/ :upgradingclientlibs_link: https://www.keycloak.org/securing-apps/upgrading +:saml_galleon_layers_link: https://www.keycloak.org/securing-apps/saml-galleon-layers :upgradingclientlibs_name: Upgrading {project_name} Client libraries :releasenotes_name: Release Notes :releasenotes_name_short: {releasenotes_name} diff --git a/docs/documentation/upgrading/topics/changes/changes-26_5_4.adoc b/docs/documentation/upgrading/topics/changes/changes-26_5_4.adoc index 92a8c1ee6f5..72358b9dd86 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_5_4.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_5_4.adoc @@ -21,3 +21,15 @@ It also lists significant changes to internal APIs. In version 26.4.0, the `server-info` endpoint changed to just return the system information for administrators in the admin realm. Nevertheless, the version property was detected to be needed by some products that interact with {project_name}. Now that property is included for administrators in the realm with permission `manage-realm`. The workaround of the `view-system` permission is more restricted too. It can only be assigned by administrators in the master realm using link:{adminguide_link}#_fine_grained_permissions[FGAP]. This permission will be deleted in a future version. + +=== Maximum inflating size for the SAML redirect binding + +Since this release, the {project_name} SAML implementation limits the data that can be inflated through the `REDIRECT` binding. The default maximum size is 128KB, the decompression stops when that value is exceeded and returns an error. The option `spi-login-protocol--saml--max-inflating-size` can be used to increase the default limit. + +.Increasing limit to 512KB +[source,bash] +---- +bin/kc.[sh|bat] --spi-login-protocol--saml--max-inflating-size=524288 +---- + +The same restriction is applied for the link:{saml_galleon_layers_link}[{project_name} SAML Galleon feature pack]. Although, in this case, you need to add a system property to the Wildfly/EAP server to change the default maximum size: `-Dorg.keycloak.adapters.saml.maxInflatingSize=524288`. diff --git a/saml-core/src/main/java/org/keycloak/saml/SAMLRequestParser.java b/saml-core/src/main/java/org/keycloak/saml/SAMLRequestParser.java index f49833774a0..c87fee183f1 100755 --- a/saml-core/src/main/java/org/keycloak/saml/SAMLRequestParser.java +++ b/saml-core/src/main/java/org/keycloak/saml/SAMLRequestParser.java @@ -18,7 +18,6 @@ package org.keycloak.saml; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; import org.keycloak.common.util.StreamUtil; @@ -27,6 +26,7 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory; import org.keycloak.saml.common.constants.GeneralConstants; 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.api.util.DeflateUtil; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.web.util.PostBindingUtil; import org.keycloak.saml.processing.web.util.RedirectBindingUtil; @@ -42,26 +42,17 @@ public class SAMLRequestParser { protected static Logger log = Logger.getLogger(SAMLRequestParser.class); public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage) { - InputStream is; - try { - is = RedirectBindingUtil.base64DeflateDecode(samlMessage); - } catch (IOException e) { - logger.samlBase64DecodingError(e); - return null; - } - if (log.isDebugEnabled()) { - String message = null; - try { - message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); - } catch (IOException e) { - throw new RuntimeException(e); - } - log.debug("SAML Redirect Binding"); - log.debug(message); - is = new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET)); + return parseRequestRedirectBinding(samlMessage, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } - } - try { + public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage, long maxInflatingSize) { + try (InputStream is = RedirectBindingUtil.base64DeflateDecode(samlMessage, maxInflatingSize)) { + if (log.isDebugEnabled()) { + String message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); + log.debug("SAML Redirect Binding"); + log.debug(message); + return SAML2Request.getSAML2ObjectFromStream(new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET))); + } return SAML2Request.getSAML2ObjectFromStream(is); } catch (Exception e) { logger.samlBase64DecodingError(e); @@ -110,27 +101,20 @@ public class SAMLRequestParser { } public static SAMLDocumentHolder parseResponseRedirectBinding(String samlMessage) { - InputStream is; - try { - is = RedirectBindingUtil.base64DeflateDecode(samlMessage); - } catch (IOException e) { - logger.samlBase64DecodingError(e); - return null; - } - if (log.isDebugEnabled()) { - String message = null; - try { - message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); - } catch (IOException e) { - throw new RuntimeException(e); - } - log.debug("SAML Redirect Binding"); - log.debug(message); - is = new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET)); + return parseResponseRedirectBinding(samlMessage, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } - } - SAML2Response response = new SAML2Response(); - try { + public static SAMLDocumentHolder parseResponseRedirectBinding(String samlMessage, long maxInflatingSize) { + try (InputStream is = RedirectBindingUtil.base64DeflateDecode(samlMessage, maxInflatingSize)) { + if (log.isDebugEnabled()) { + String message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); + log.debug("SAML Redirect Binding"); + log.debug(message); + SAML2Response response = new SAML2Response(); + response.getSAML2ObjectFromStream(new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET))); + return response.getSamlDocumentHolder(); + } + SAML2Response response = new SAML2Response(); response.getSAML2ObjectFromStream(is); return response.getSamlDocumentHolder(); } catch (Exception e) { diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/api/util/DeflateUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/api/util/DeflateUtil.java index 471492ab5e7..cd64bb2874b 100755 --- a/saml-core/src/main/java/org/keycloak/saml/processing/api/util/DeflateUtil.java +++ b/saml-core/src/main/java/org/keycloak/saml/processing/api/util/DeflateUtil.java @@ -35,6 +35,15 @@ import org.keycloak.saml.common.constants.GeneralConstants; */ public class DeflateUtil { + /** + * Maximum size for inflating. Default is 128KB like quarkus.http.limits.max-form-attribute-size. + */ + public static long DEFAULT_MAX_INFLATING_SIZE = 131072; + + private DeflateUtil() { + // utility class + } + /** * Apply DEFLATE encoding * @@ -75,7 +84,90 @@ public class DeflateUtil { * @return */ public static InputStream decode(byte[] msgToDecode) { + return decode(msgToDecode, DEFAULT_MAX_INFLATING_SIZE); + } + + /** + * DEFLATE decoding + * + * @param msgToDecode the message that needs decoding + * @param maxInflatingSize the maximum size to inflate, IOExceptio is thrown if more data is inflated + * + * @return + */ + public static InputStream decode(byte[] msgToDecode, long maxInflatingSize) { ByteArrayInputStream bais = new ByteArrayInputStream(msgToDecode); - return new InflaterInputStream(bais, new Inflater(true)); + return new LimitedInflaterInputStream(bais, maxInflatingSize); + } + + private static class LimitedInflaterInputStream extends InputStream { + + private final InflaterInputStream is; + private final Inflater inflater; + private final long maxInflatingSize; + + private LimitedInflaterInputStream(InputStream is, long maxInflatingSize) { + this.inflater = new Inflater(true); + this.is = new InflaterInputStream(is, inflater); + this.maxInflatingSize = maxInflatingSize; + } + + private void checkMaxInflatingsize() throws IOException { + if (inflater.getBytesWritten() > maxInflatingSize) { + throw new IOException(String.format("Maximum inflating size %d reached. Total bytes witten %d.", + maxInflatingSize, inflater.getTotalOut())); + } + } + + @Override + public int read() throws IOException { + int result = is.read(); + checkMaxInflatingsize(); + return result; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int result = is.read(b, off, len); + checkMaxInflatingsize(); + return result; + } + + @Override + public int read(byte[] b) throws IOException { + int result = is.read(b); + checkMaxInflatingsize(); + return result; + } + + @Override + public boolean markSupported() { + return false; + } + + @Override + public void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + @Override + public void mark(int readlimit) { + // nothing + } + + @Override + public void close() throws IOException { + is.close(); + } + + @Override + public int available() throws IOException { + return is.available(); + } + + @Override + public long skip(long n) throws IOException { + return is.skip(n); + } } } \ No newline at end of file diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/web/util/RedirectBindingUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/web/util/RedirectBindingUtil.java index 589ae8ecc34..0553926d85c 100755 --- a/saml-core/src/main/java/org/keycloak/saml/processing/web/util/RedirectBindingUtil.java +++ b/saml-core/src/main/java/org/keycloak/saml/processing/web/util/RedirectBindingUtil.java @@ -152,8 +152,22 @@ public class RedirectBindingUtil { * @throws IOException */ public static InputStream urlBase64DeflateDecode(String encodedString) throws IOException { + return urlBase64DeflateDecode(encodedString, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } + + /** + * Apply URL decoding, followed by base64 decoding followed by deflate decompression + * + * @param encodedString + * @param maxInflatingSize + * + * @return + * + * @throws IOException + */ + public static InputStream urlBase64DeflateDecode(String encodedString, long maxInflatingSize) throws IOException { byte[] deflatedString = urlBase64Decode(encodedString); - return DeflateUtil.decode(deflatedString); + return DeflateUtil.decode(deflatedString, maxInflatingSize); } /** @@ -166,8 +180,22 @@ public class RedirectBindingUtil { * @throws IOException */ public static InputStream base64DeflateDecode(String encodedString) throws IOException { + return base64DeflateDecode(encodedString, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } + + /** + * Base64 decode followed by Deflate decoding + * + * @param encodedString + * @param maxInflatingSize + * + * @return + * + * @throws IOException + */ + public static InputStream base64DeflateDecode(String encodedString, long maxInflatingSize) throws IOException { byte[] base64decodedMsg = Base64.getMimeDecoder().decode(encodedString); - return DeflateUtil.decode(base64decodedMsg); + return DeflateUtil.decode(base64decodedMsg, maxInflatingSize); } /** diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java index 8f5728e9668..933dc2b16f6 100755 --- a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java +++ b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java @@ -91,6 +91,7 @@ import org.keycloak.protocol.saml.SamlMetadataKeyLocator; import org.keycloak.protocol.saml.SamlMetadataPublicKeyLoader; import org.keycloak.protocol.saml.SamlPrincipalType; import org.keycloak.protocol.saml.SamlProtocol; +import org.keycloak.protocol.saml.SamlProtocolFactory; import org.keycloak.protocol.saml.SamlProtocolUtils; import org.keycloak.protocol.saml.SamlService; import org.keycloak.protocol.saml.SamlSessionUtils; @@ -154,6 +155,7 @@ public class SAMLEndpoint { protected final KeycloakSession session; protected final ClientConnection clientConnection; protected final HttpHeaders headers; + protected final long maxInflatingSize; public SAMLEndpoint(KeycloakSession session, SAMLIdentityProvider provider, SAMLIdentityProviderConfig config, UserAuthenticationIdentityProvider.AuthenticationCallback callback, DestinationValidator destinationValidator) { @@ -165,6 +167,8 @@ public class SAMLEndpoint { this.session = session; this.clientConnection = session.getContext().getConnection(); this.headers = session.getContext().getRequestHeaders(); + SamlProtocolFactory factory = (SamlProtocolFactory) session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, SamlProtocol.LOGIN_PROTOCOL); + this.maxInflatingSize = factory.getMaxInflatingSize(); } @GET @@ -298,6 +302,12 @@ public class SAMLEndpoint { protected Response handleSamlRequest(String samlRequest, String relayState) { SAMLDocumentHolder holder = extractRequestDocument(samlRequest); + if (holder == null) { + event.event(EventType.IDENTITY_PROVIDER_RESPONSE); + event.detail(Details.REASON, Errors.INVALID_SAML_DOCUMENT); + event.error(Errors.INVALID_REQUEST); + return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_REQUEST); + } RequestAbstractType requestAbstractType = (RequestAbstractType) holder.getSamlObject(); // validate destination if (isDestinationRequired() && @@ -878,12 +888,12 @@ public class SAMLEndpoint { @Override protected SAMLDocumentHolder extractRequestDocument(String samlRequest) { - return SAMLRequestParser.parseRequestRedirectBinding(samlRequest); + return SAMLRequestParser.parseRequestRedirectBinding(samlRequest, maxInflatingSize); } @Override protected SAMLDocumentHolder extractResponseDocument(String response) { - return SAMLRequestParser.parseResponseRedirectBinding(response); + return SAMLRequestParser.parseResponseRedirectBinding(response, maxInflatingSize); } @Override diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java index 475ccb4aecf..1028b54253f 100755 --- a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java +++ b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java @@ -40,10 +40,13 @@ import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory; import org.keycloak.protocol.saml.mappers.AttributeStatementHelper; import org.keycloak.protocol.saml.mappers.RoleListMapper; import org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.provider.ProviderConfigurationBuilder; import org.keycloak.representations.idm.CertificateRepresentation; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.saml.SignatureAlgorithm; import org.keycloak.saml.common.constants.JBossSAMLURIConstants; +import org.keycloak.saml.processing.api.util.DeflateUtil; import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants; import org.keycloak.saml.validators.DestinationValidator; @@ -57,10 +60,11 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory { private static final String ROLE_LIST_CONSENT_TEXT = "${samlRoleListScopeConsentText}"; private DestinationValidator destinationValidator; + private long maxInflatingSize; @Override public Object createProtocolEndpoint(KeycloakSession session, EventBuilder event) { - return new SamlService(session, event, destinationValidator); + return new SamlService(session, event, maxInflatingSize, destinationValidator); } @Override @@ -103,6 +107,7 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory { defaultBuiltins.add(model); } this.destinationValidator = DestinationValidator.forProtocolMap(config.getArray("knownProtocols")); + this.maxInflatingSize = config.getLong("maxInflatingSize", DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); } @Override @@ -202,4 +207,24 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory { public int order() { return OIDCLoginProtocolFactory.UI_ORDER - 10; } + + /** + * Getter for the max inflating size + * @return + */ + public long getMaxInflatingSize() { + return maxInflatingSize; + } + + @Override + public List getConfigMetadata() { + return ProviderConfigurationBuilder.create() + .property() + .name("maxInflatingSize") + .type("long") + .helpText("The maximum inflating size in bytes for the REDIRECT binding.") + .defaultValue(DeflateUtil.DEFAULT_MAX_INFLATING_SIZE) + .add() + .build(); + } } diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java index da82ca6b006..a34873fe4b8 100755 --- a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java +++ b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java @@ -159,10 +159,12 @@ public class SamlService extends AuthorizationEndpointBase { public static final String ARTIFACT_RESOLUTION_SERVICE_PATH = "resolve"; private final DestinationValidator destinationValidator; + private final long maxInflatingSize; - public SamlService(KeycloakSession session, EventBuilder event, DestinationValidator destinationValidator) { + public SamlService(KeycloakSession session, EventBuilder event, long maxInflatingSize, DestinationValidator destinationValidator) { super(session, event); this.destinationValidator = destinationValidator; + this.maxInflatingSize = maxInflatingSize; } public abstract class BindingProtocol { @@ -204,7 +206,7 @@ public class SamlService extends AuthorizationEndpointBase { event.event(EventType.LOGOUT); SAMLDocumentHolder holder = extractResponseDocument(samlResponse); - if (! (holder.getSamlObject() instanceof StatusResponseType)) { + if (holder == null || !(holder.getSamlObject() instanceof StatusResponseType)) { event.detail(Details.REASON, Errors.INVALID_SAML_RESPONSE); event.error(Errors.INVALID_SAML_RESPONSE); return error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_REQUEST); @@ -848,12 +850,12 @@ public class SamlService extends AuthorizationEndpointBase { @Override protected SAMLDocumentHolder extractRequestDocument(String samlRequest) { - return SAMLRequestParser.parseRequestRedirectBinding(samlRequest); + return SAMLRequestParser.parseRequestRedirectBinding(samlRequest, maxInflatingSize); } @Override protected SAMLDocumentHolder extractResponseDocument(String response) { - return SAMLRequestParser.parseResponseRedirectBinding(response); + return SAMLRequestParser.parseResponseRedirectBinding(response, maxInflatingSize); } @Override @@ -1120,7 +1122,7 @@ public class SamlService extends AuthorizationEndpointBase { @NoCache @Consumes({"application/soap+xml",MediaType.TEXT_XML}) public Response soapBinding(InputStream inputStream) { - SamlEcpProfileService bindingService = new SamlEcpProfileService(session, event, destinationValidator); + SamlEcpProfileService bindingService = new SamlEcpProfileService(session, event, maxInflatingSize, destinationValidator); return bindingService.authenticate(inputStream); } diff --git a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java index 6d56735e12b..517a29c0148 100755 --- a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java +++ b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java @@ -59,8 +59,8 @@ public class SamlEcpProfileService extends SamlService { private static final String NS_PREFIX_SAML_PROTOCOL = "samlp"; private static final String NS_PREFIX_SAML_ASSERTION = "saml"; - public SamlEcpProfileService(KeycloakSession session, EventBuilder event, DestinationValidator destinationValidator) { - super(session, event, destinationValidator); + public SamlEcpProfileService(KeycloakSession session, EventBuilder event, long maxInflatingSize, DestinationValidator destinationValidator) { + super(session, event, maxInflatingSize, destinationValidator); } public Response authenticate(InputStream inputStream) { diff --git a/services/src/test/java/org/keycloak/test/broker/saml/SAMLParsingTest.java b/services/src/test/java/org/keycloak/test/broker/saml/SAMLParsingTest.java index 5e6c14f8769..c0093be3585 100644 --- a/services/src/test/java/org/keycloak/test/broker/saml/SAMLParsingTest.java +++ b/services/src/test/java/org/keycloak/test/broker/saml/SAMLParsingTest.java @@ -17,12 +17,14 @@ package org.keycloak.test.broker.saml; +import java.io.IOException; import java.util.Base64; import org.keycloak.saml.SAMLRequestParser; import org.keycloak.saml.common.constants.GeneralConstants; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.web.util.PostBindingUtil; +import org.keycloak.saml.processing.web.util.RedirectBindingUtil; import org.junit.Assert; import org.junit.Test; @@ -35,6 +37,7 @@ import org.junit.Test; public class SAMLParsingTest { private static final String SAML_RESPONSE = "http://localhost:8082/auth/realms/realm-with-saml-idp-basic"; + private static final String SAML_REQUEST = "http://localhost:8080/realms/master"; @Test public void parseTest() { @@ -51,4 +54,19 @@ public class SAMLParsingTest { SAMLDocumentHolder holder = SAMLRequestParser.parseResponseDocument(samlBytes); Assert.assertNotNull(holder); } + + @Test + public void parseRequestResponseRedirectBinding() throws IOException { + String encodedResponse = RedirectBindingUtil.deflateBase64Encode(SAML_RESPONSE.getBytes(GeneralConstants.SAML_CHARSET_NAME)); + SAMLDocumentHolder holder = SAMLRequestParser.parseResponseRedirectBinding(encodedResponse, SAML_RESPONSE.length()); + Assert.assertNotNull(holder); + holder = SAMLRequestParser.parseResponseRedirectBinding(encodedResponse, SAML_RESPONSE.length() - 1); + Assert.assertNull(holder); + + String encodedRequest = RedirectBindingUtil.deflateBase64Encode(SAML_REQUEST.getBytes(GeneralConstants.SAML_CHARSET_NAME)); + holder = SAMLRequestParser.parseRequestRedirectBinding(encodedRequest, SAML_REQUEST.length()); + Assert.assertNotNull(holder); + holder = SAMLRequestParser.parseRequestRedirectBinding(encodedRequest, SAML_RESPONSE.length() - 1); + Assert.assertNull(holder); + } }