Fix for KEYCLOAK-18914 (#9355)
Closed #9382 Co-authored-by: Hans-Christian Halfbrodt <hc-github42@halfbrodt.org>
This commit is contained in:
parent
1cebd79f1c
commit
d9d77fe1f7
12 changed files with 235 additions and 1159 deletions
|
@ -33,6 +33,7 @@ import org.keycloak.adapters.spi.AuthChallenge;
|
|||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||
|
@ -57,7 +58,6 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
|
|||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
import org.keycloak.saml.common.util.DocumentUtil;
|
||||
import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
|
||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.keycloak.common.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* <p>Encodes and decodes to and from Base64 notation.</p>
|
||||
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
|
||||
|
@ -35,6 +37,10 @@ package org.keycloak.common.util;
|
|||
* Change Log:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>v2.3.8 - Fixed automatic gzip decoding, based on the content,
|
||||
* as this may lead to unexpected behaviour. Request either gzipped
|
||||
* or non gzipped decoding as excepted. Automatic encoding is especially
|
||||
* problematic with generated input (see KEYCLOAK-18914 for a detailed case).</li>
|
||||
* <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the
|
||||
* value 01111111, which is an invalid base 64 character but should not
|
||||
* throw an ArrayIndexOutOfBoundsException either. Led to discovery of
|
||||
|
@ -76,7 +82,7 @@ package org.keycloak.common.util;
|
|||
* <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
|
||||
* <li><em>Throws exceptions instead of returning null values.</em> Because some operations
|
||||
* (especially those that may permit the GZIP option) use IO streams, there
|
||||
* is a possiblity of an java.io.IOException being thrown. After some discussion and
|
||||
* is a possibility of an java.io.IOException being thrown. After some discussion and
|
||||
* thought, I've changed the behavior of the methods to throw java.io.IOExceptions
|
||||
* rather than return null if ever there's an error. I think this is more
|
||||
* appropriate, though it will require some changes to your code. Sorry,
|
||||
|
@ -167,9 +173,8 @@ public class Base64
|
|||
/** Specify that data should be gzip-compressed in second bit. Value is two. */
|
||||
public final static int GZIP = 2;
|
||||
|
||||
/** Specify that gzipped data should <em>not</em> be automatically gunzipped. */
|
||||
public final static int DONT_GUNZIP = 4;
|
||||
|
||||
/** Specify that data should be gunzipped. */
|
||||
public final static int GUNZIP = 4;
|
||||
|
||||
/** Do break lines when encoding. Value is 8. */
|
||||
public final static int DO_BREAK_LINES = 8;
|
||||
|
@ -179,7 +184,7 @@ public class Base64
|
|||
* in Section 4 of RFC3548:
|
||||
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
|
||||
* It is important to note that data encoded this way is <em>not</em> officially valid Base64,
|
||||
* or at the very least should not be called Base64 without also specifying that is
|
||||
* or at the very least should not be called Base64 without also specifying that it
|
||||
* was encoded using the URL- and Filename-safe dialect.
|
||||
*/
|
||||
public final static int URL_SAFE = 16;
|
||||
|
@ -476,7 +481,7 @@ public class Base64
|
|||
* anywhere along their length by specifying
|
||||
* <var>srcOffset</var> and <var>destOffset</var>.
|
||||
* This method does not check to make sure your arrays
|
||||
* are large enough to accomodate <var>srcOffset</var> + 3 for
|
||||
* are large enough to accommodate <var>srcOffset</var> + 3 for
|
||||
* the <var>source</var> array or <var>destOffset</var> + 4 for
|
||||
* the <var>destination</var> array.
|
||||
* The actual number of significant bytes in your array is
|
||||
|
@ -548,7 +553,7 @@ public class Base64
|
|||
* writing it to the <code>encoded</code> ByteBuffer.
|
||||
* This is an experimental feature. Currently it does not
|
||||
* pass along any options (such as {@link #DO_BREAK_LINES}
|
||||
* or {@link #GZIP}.
|
||||
* or {@link #GZIP}).
|
||||
*
|
||||
* @param raw input buffer
|
||||
* @param encoded output buffer
|
||||
|
@ -733,7 +738,7 @@ public class Base64
|
|||
* Example options:<pre>
|
||||
* GZIP: gzip-compresses object before encoding it.
|
||||
* DO_BREAK_LINES: break lines at 76 characters
|
||||
* <i>Note: Technically, this makes your encoding non-compliant.</i>
|
||||
* <i>Note: Technically, without line break your encoding may become non-compliant (see rfc2045 and rfc4648).</i>
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
|
||||
|
@ -1115,15 +1120,8 @@ public class Base64
|
|||
* @return decoded data
|
||||
* @since 2.3.1
|
||||
*/
|
||||
public static byte[] decode( byte[] source )
|
||||
throws java.io.IOException {
|
||||
byte[] decoded = null;
|
||||
// try {
|
||||
decoded = decode( source, 0, source.length, Base64.NO_OPTIONS );
|
||||
// } catch( java.io.IOException ex ) {
|
||||
// assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
|
||||
// }
|
||||
return decoded;
|
||||
public static byte[] decode( byte[] source ) throws java.io.IOException {
|
||||
return decode( source, 0, source.length, Base64.NO_OPTIONS );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1231,9 +1229,9 @@ public class Base64
|
|||
* detecting gzip-compressed data and decompressing it.
|
||||
*
|
||||
* @param s the string to decode
|
||||
* @param options encode options such as URL_SAFE
|
||||
* @param options decode options such as URL_SAFE or GUNZIP
|
||||
* @return the decoded data
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @throws java.io.IOException if there is an error (invalid character in source string or gunzip error)
|
||||
* @throws NullPointerException if <tt>s</tt> is null
|
||||
* @since 1.4
|
||||
*/
|
||||
|
@ -1257,46 +1255,41 @@ public class Base64
|
|||
|
||||
// Check to see if it's gzip-compressed
|
||||
// GZIP Magic Two-Byte Number: 0x8b1f (35615)
|
||||
boolean dontGunzip = (options & DONT_GUNZIP) != 0;
|
||||
if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {
|
||||
boolean doGunzip = (options & GUNZIP) != 0;
|
||||
if( (bytes != null) && (bytes.length >= 4) && doGunzip ) {
|
||||
|
||||
int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
|
||||
if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) {
|
||||
java.io.ByteArrayInputStream bais = null;
|
||||
java.util.zip.GZIPInputStream gzis = null;
|
||||
java.io.ByteArrayOutputStream baos = null;
|
||||
byte[] buffer = new byte[2048];
|
||||
int length = 0;
|
||||
if( java.util.zip.GZIPInputStream.GZIP_MAGIC != head ) {
|
||||
throw new IOException("Provided data has no GZIP magic header.");
|
||||
}
|
||||
java.io.ByteArrayInputStream bais = null;
|
||||
java.util.zip.GZIPInputStream gzis = null;
|
||||
java.io.ByteArrayOutputStream baos = null;
|
||||
byte[] buffer = new byte[2048];
|
||||
int length = 0;
|
||||
|
||||
try {
|
||||
baos = new java.io.ByteArrayOutputStream();
|
||||
bais = new java.io.ByteArrayInputStream( bytes );
|
||||
gzis = new java.util.zip.GZIPInputStream( bais );
|
||||
try {
|
||||
baos = new java.io.ByteArrayOutputStream();
|
||||
bais = new java.io.ByteArrayInputStream( bytes );
|
||||
gzis = new java.util.zip.GZIPInputStream( bais );
|
||||
|
||||
while( ( length = gzis.read( buffer ) ) >= 0 ) {
|
||||
baos.write(buffer,0,length);
|
||||
} // end while: reading input
|
||||
while( ( length = gzis.read( buffer ) ) >= 0 ) {
|
||||
baos.write(buffer,0,length);
|
||||
} // end while: reading input
|
||||
|
||||
// No error? Get new bytes.
|
||||
bytes = baos.toByteArray();
|
||||
// No error? Get new bytes.
|
||||
bytes = baos.toByteArray();
|
||||
|
||||
} // end try
|
||||
catch( java.io.IOException e ) {
|
||||
if (e.getMessage().equals("Unsupported compression method")) {
|
||||
System.out.println("Base64 decoding: Ignoring GZIP header and just returning originally-decoded bytes."); // Better to log as debug, but jboss logging not available in the module :/
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} // end try
|
||||
catch( java.io.IOException e ) {
|
||||
throw new IOException("Failed to gunzip", e);
|
||||
} // end catch
|
||||
finally {
|
||||
try{ baos.close(); } catch( Exception e ){}
|
||||
try{ gzis.close(); } catch( Exception e ){}
|
||||
try{ bais.close(); } catch( Exception e ){}
|
||||
} // end finally
|
||||
|
||||
// Just return originally-decoded bytes
|
||||
} // end catch
|
||||
finally {
|
||||
try{ baos.close(); } catch( Exception e ){}
|
||||
try{ gzis.close(); } catch( Exception e ){}
|
||||
try{ bais.close(); } catch( Exception e ){}
|
||||
} // end finally
|
||||
|
||||
} // end if: gzipped
|
||||
} // end if: bytes.length >= 2
|
||||
|
||||
return bytes;
|
||||
|
|
|
@ -31,8 +31,7 @@ public class Base64Url {
|
|||
public static byte[] decode(String s) {
|
||||
s = encodeBase64UrlToBase64(s);
|
||||
try {
|
||||
// KEYCLOAK-2479 : Avoid to try gzip decoding as for some objects, it may display exception to STDERR. And we know that object wasn't encoded as GZIP
|
||||
return Base64.decode(s, Base64.DONT_GUNZIP);
|
||||
return Base64.decode(s);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package org.keycloak.common.util;
|
||||
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* Test for BASE64 decode implementation.
|
||||
*
|
||||
* @author <a href="mailto:keycloak-hc@halfbrodt.org">Hans-Christian Halfbrodt</a>
|
||||
*/
|
||||
public class Base64DecodeTest {
|
||||
|
||||
@Test
|
||||
public void decode_simple() throws IOException {
|
||||
// high level string variant
|
||||
final String testData = "test data";
|
||||
final String encoded = "dGVzdCBkYXRh";
|
||||
final String decoded = new String(Base64.decode(encoded));
|
||||
assertThat(decoded, equalTo(testData));
|
||||
|
||||
// low level byte array variant
|
||||
final byte[] encoded2 = encoded.getBytes();
|
||||
final String decoded2 = new String(Base64.decode(encoded2));
|
||||
assertThat(decoded2, equalTo(testData));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decode_doNotUseGzip() throws IOException {
|
||||
// Input has gzip magic byte by coincidence and should not be gunzipped. (KEYCLOAK-18914)
|
||||
// high level string variant
|
||||
final byte[] testData = new byte[]{
|
||||
31, -117, 8, -56, 1, 1, 1, 1, 1, 1, 43, 73, 45, 46,
|
||||
81, 72, 73, 44, 73, 4, 1, -78, -82, 8, -45, 9, 1, 1, 1};
|
||||
final String encoded = "H4sIyAEBAQEBAStJLS5RSEksSQQBsq4I0wkBAQE=";
|
||||
final byte[] decoded = Base64.decode(encoded);
|
||||
assertThat(decoded, equalTo(testData));
|
||||
|
||||
// low level byte array variant
|
||||
final byte[] encoded2 = encoded.getBytes();
|
||||
final byte[] decoded2 = Base64.decode(encoded2);
|
||||
assertThat(decoded2, equalTo(testData));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decode_gzip() throws IOException {
|
||||
// high level string variant
|
||||
final String testData = "test data";
|
||||
final String encoded = "H4sIAAAAAAAAACtJLS5RSEksSQQAsq4I0wkAAAA=";
|
||||
final String decoded = new String(Base64.decode(encoded, Base64.GUNZIP));
|
||||
assertThat(decoded, equalTo(testData));
|
||||
|
||||
// low level byte array variant
|
||||
// specified to ignore gunzip option (see javadoc)
|
||||
final byte[] expected2 = new byte[]{
|
||||
31, -117, 8, 0, 0, 0, 0, 0, 0, 0, 43, 73,
|
||||
45, 46, 81, 72, 73, 44, 73, 4, 0, -78, -82,
|
||||
8, -45, 9, 0, 0, 0};
|
||||
final byte[] encoded2 = encoded.getBytes();
|
||||
final byte[] decoded2 = Base64.decode(encoded2, 0, encoded2.length, Base64.GUNZIP);
|
||||
assertThat(decoded2, equalTo(expected2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decode_empty() throws IOException {
|
||||
final byte[] result = Base64.decode("");
|
||||
assertThat(result, equalTo(new byte[0]));
|
||||
final byte[] result2 = Base64.decode(new byte[0]);
|
||||
assertThat(result2, equalTo(new byte[0]));
|
||||
|
||||
try {
|
||||
Base64.decode(" ");
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e) {
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
}
|
||||
|
||||
try {
|
||||
Base64.decode(" ".getBytes());
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e) {
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
}
|
||||
|
||||
try {
|
||||
Base64.decode((String) null);
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e) {
|
||||
assertThat(e, instanceOf(NullPointerException.class));
|
||||
}
|
||||
|
||||
try {
|
||||
Base64.decode((byte[]) null);
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e) {
|
||||
assertThat(e, instanceOf(NullPointerException.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decode_lowLevelInvalidParams() {
|
||||
try {
|
||||
Base64.decode(null, 0, 1, Base64.NO_OPTIONS);
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e){
|
||||
assertThat(e, instanceOf(NullPointerException.class));
|
||||
}
|
||||
|
||||
try {
|
||||
Base64.decode(new byte[2], 0, 1, Base64.NO_OPTIONS);
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e){
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
}
|
||||
|
||||
try {
|
||||
Base64.decode(new byte[8], 0, 10, Base64.NO_OPTIONS);
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e){
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
}
|
||||
|
||||
try {
|
||||
Base64.decode(new byte[8], 5, 5, Base64.NO_OPTIONS);
|
||||
MatcherAssert.assertThat("Exception excepted", false);
|
||||
} catch (final Exception e){
|
||||
assertThat(e, instanceOf(IllegalArgumentException.class));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,9 +17,9 @@
|
|||
|
||||
package org.keycloak.dom.xmlsec.w3.xmldsig;
|
||||
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.saml.common.constants.WSTrustConstants;
|
||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
|
@ -201,14 +201,13 @@ public class DSAKeyValueType implements KeyValueType {
|
|||
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
||||
*/
|
||||
public DSAPublicKey convertToPublicKey() throws ProcessingException {
|
||||
BigInteger BigY, BigP, BigQ, BigG;
|
||||
|
||||
BigY = new BigInteger(1, massage(Base64.decode(new String(y))));
|
||||
BigP = new BigInteger(1, massage(Base64.decode(new String(p))));
|
||||
BigQ = new BigInteger(1, massage(Base64.decode(new String(q))));
|
||||
BigG = new BigInteger(1, massage(Base64.decode(new String(g))));
|
||||
|
||||
try {
|
||||
BigInteger BigY = new BigInteger(1, massage(Base64.decode(new String(y))));
|
||||
BigInteger BigP = new BigInteger(1, massage(Base64.decode(new String(p))));
|
||||
BigInteger BigQ = new BigInteger(1, massage(Base64.decode(new String(q))));
|
||||
BigInteger BigG = new BigInteger(1, massage(Base64.decode(new String(g))));
|
||||
|
||||
KeyFactory dsaKeyFactory = KeyFactory.getInstance("dsa");
|
||||
DSAPublicKeySpec kspec = new DSAPublicKeySpec(BigY, BigP, BigQ, BigG);
|
||||
return (DSAPublicKey) dsaKeyFactory.generatePublic(kspec);
|
||||
|
@ -225,14 +224,13 @@ public class DSAKeyValueType implements KeyValueType {
|
|||
* @throws ProcessingException
|
||||
*/
|
||||
public DSAPrivateKey convertToPrivateKey() throws ProcessingException {
|
||||
BigInteger BigY, BigP, BigQ, BigG;
|
||||
|
||||
BigY = new BigInteger(1, massage(Base64.decode(new String(y))));
|
||||
BigP = new BigInteger(1, massage(Base64.decode(new String(p))));
|
||||
BigQ = new BigInteger(1, massage(Base64.decode(new String(q))));
|
||||
BigG = new BigInteger(1, massage(Base64.decode(new String(g))));
|
||||
|
||||
try {
|
||||
BigInteger BigY = new BigInteger(1, massage(Base64.decode(new String(y))));
|
||||
BigInteger BigP = new BigInteger(1, massage(Base64.decode(new String(p))));
|
||||
BigInteger BigQ = new BigInteger(1, massage(Base64.decode(new String(q))));
|
||||
BigInteger BigG = new BigInteger(1, massage(Base64.decode(new String(g))));
|
||||
|
||||
KeyFactory dsaKeyFactory = KeyFactory.getInstance("dsa");
|
||||
DSAPrivateKeySpec kspec = new DSAPrivateKeySpec(BigY, BigP, BigQ, BigG);
|
||||
return (DSAPrivateKey) dsaKeyFactory.generatePrivate(kspec);
|
||||
|
@ -300,4 +298,4 @@ public class DSAKeyValueType implements KeyValueType {
|
|||
}
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
|
||||
package org.keycloak.dom.xmlsec.w3.xmldsig;
|
||||
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.saml.common.constants.WSTrustConstants;
|
||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
|
@ -97,10 +97,9 @@ public class RSAKeyValueType implements KeyValueType {
|
|||
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
||||
*/
|
||||
public RSAPublicKey convertToPublicKey() throws ProcessingException {
|
||||
BigInteger bigModulus = new BigInteger(1, massage(Base64.decode(new String(modulus))));
|
||||
BigInteger bigEx = new BigInteger(1, massage(Base64.decode(new String(exponent))));
|
||||
|
||||
try {
|
||||
BigInteger bigModulus = new BigInteger(1, massage(Base64.decode(new String(modulus))));
|
||||
BigInteger bigEx = new BigInteger(1, massage(Base64.decode(new String(exponent))));
|
||||
KeyFactory rsaKeyFactory = KeyFactory.getInstance("rsa");
|
||||
RSAPublicKeySpec kspec = new RSAPublicKeySpec(bigModulus, bigEx);
|
||||
return (RSAPublicKey) rsaKeyFactory.generatePublic(kspec);
|
||||
|
@ -117,10 +116,9 @@ public class RSAKeyValueType implements KeyValueType {
|
|||
* @throws ProcessingException
|
||||
*/
|
||||
public RSAPrivateKey convertToPrivateKey() throws ProcessingException {
|
||||
BigInteger bigModulus = new BigInteger(1, massage(Base64.decode(new String(modulus))));
|
||||
BigInteger bigEx = new BigInteger(1, massage(Base64.decode(new String(exponent))));
|
||||
|
||||
try {
|
||||
BigInteger bigModulus = new BigInteger(1, massage(Base64.decode(new String(modulus))));
|
||||
BigInteger bigEx = new BigInteger(1, massage(Base64.decode(new String(exponent))));
|
||||
KeyFactory rsaKeyFactory = KeyFactory.getInstance("rsa");
|
||||
RSAPrivateKeySpec kspec = new RSAPrivateKeySpec(bigModulus, bigEx);
|
||||
return (RSAPrivateKey) rsaKeyFactory.generatePrivate(kspec);
|
||||
|
@ -160,4 +158,4 @@ public class RSAKeyValueType implements KeyValueType {
|
|||
}
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,7 +43,12 @@ public class SAMLRequestParser {
|
|||
|
||||
public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage) {
|
||||
InputStream is;
|
||||
is = RedirectBindingUtil.base64DeflateDecode(samlMessage);
|
||||
try {
|
||||
is = RedirectBindingUtil.base64DeflateDecode(samlMessage);
|
||||
} catch (IOException e) {
|
||||
logger.samlBase64DecodingError(e);
|
||||
return null;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
String message = null;
|
||||
try {
|
||||
|
@ -105,7 +110,13 @@ public class SAMLRequestParser {
|
|||
}
|
||||
|
||||
public static SAMLDocumentHolder parseResponseRedirectBinding(String samlMessage) {
|
||||
InputStream is = RedirectBindingUtil.base64DeflateDecode(samlMessage);
|
||||
InputStream is;
|
||||
try {
|
||||
is = RedirectBindingUtil.base64DeflateDecode(samlMessage);
|
||||
} catch (IOException e) {
|
||||
logger.samlBase64DecodingError(e);
|
||||
return null;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
String message = null;
|
||||
try {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.keycloak.saml.processing.core.saml.v2.util;
|
||||
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
|
||||
import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
|
||||
import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
|
||||
|
@ -24,14 +25,8 @@ import org.keycloak.saml.common.PicketLinkLogger;
|
|||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLConstants;
|
||||
import org.keycloak.saml.common.constants.WSTrustConstants;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
import org.keycloak.saml.processing.core.constants.PicketLinkFederationConstants;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
@ -220,4 +215,4 @@ public class SignatureUtil {
|
|||
throw logger.signatureUnknownAlgo(algo);
|
||||
return sig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.keycloak.saml.processing.core.util;
|
||||
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
|
||||
import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
|
||||
|
@ -28,7 +29,6 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
|
|||
import org.keycloak.saml.common.constants.WSTrustConstants;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
import org.keycloak.saml.common.util.DocumentUtil;
|
||||
import org.keycloak.saml.common.util.StringUtil;
|
||||
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
||||
|
@ -519,7 +519,7 @@ public class XMLSignatureUtil {
|
|||
DOMValidateContext valContext = new DOMValidateContext(validationKeySelector, signatureNode);
|
||||
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
|
||||
boolean coreValidity = signature.validate(valContext);
|
||||
|
||||
|
||||
if (! coreValidity) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
boolean sv = signature.getSignatureValue().validate(valContext);
|
||||
|
@ -758,4 +758,4 @@ public class XMLSignatureUtil {
|
|||
|
||||
return keyInfoFactory.newKeyInfo(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
*/
|
||||
package org.keycloak.saml.processing.web.util;
|
||||
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.saml.common.PicketLinkLogger;
|
||||
import org.keycloak.saml.common.PicketLinkLoggerFactory;
|
||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -43,7 +43,7 @@ public class PostBindingUtil {
|
|||
* @return
|
||||
*/
|
||||
public static String base64Encode(String stringToEncode) throws IOException {
|
||||
return Base64.encodeBytes(stringToEncode.getBytes(GeneralConstants.SAML_CHARSET), Base64.DONT_BREAK_LINES);
|
||||
return Base64.encodeBytes(stringToEncode.getBytes(GeneralConstants.SAML_CHARSET));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +57,12 @@ public class PostBindingUtil {
|
|||
if (encodedString == null)
|
||||
throw logger.nullArgumentError("encodedString");
|
||||
|
||||
return Base64.decode(encodedString);
|
||||
try {
|
||||
return Base64.decode(encodedString);
|
||||
} catch (Exception e) {
|
||||
logger.error(e);
|
||||
throw logger.invalidArgumentError("base64 decode failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,4 +92,4 @@ public class PostBindingUtil {
|
|||
|
||||
return escaped.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
package org.keycloak.saml.processing.web.util;
|
||||
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||
import org.keycloak.saml.common.util.Base64;
|
||||
import org.keycloak.saml.common.util.StringUtil;
|
||||
import org.keycloak.saml.processing.api.util.DeflateUtil;
|
||||
|
||||
|
@ -70,7 +70,7 @@ public class RedirectBindingUtil {
|
|||
* @throws IOException
|
||||
*/
|
||||
public static String base64Encode(byte[] stringToEncode) throws IOException {
|
||||
return Base64.encodeBytes(stringToEncode, Base64.DONT_BREAK_LINES);
|
||||
return Base64.encodeBytes(stringToEncode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,7 +83,7 @@ public class RedirectBindingUtil {
|
|||
* @throws IOException
|
||||
*/
|
||||
public static String base64URLEncode(byte[] stringToEncode) throws IOException {
|
||||
String base64Request = Base64.encodeBytes(stringToEncode, Base64.DONT_BREAK_LINES);
|
||||
String base64Request = Base64.encodeBytes(stringToEncode);
|
||||
return urlEncode(base64Request);
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ public class RedirectBindingUtil {
|
|||
*/
|
||||
public static String deflateBase64Encode(byte[] stringToEncode) throws IOException {
|
||||
byte[] deflatedMsg = DeflateUtil.encode(stringToEncode);
|
||||
return Base64.encodeBytes(deflatedMsg, Base64.DONT_BREAK_LINES);
|
||||
return Base64.encodeBytes(deflatedMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,8 +162,10 @@ public class RedirectBindingUtil {
|
|||
* @param encodedString
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static InputStream base64DeflateDecode(String encodedString) {
|
||||
public static InputStream base64DeflateDecode(String encodedString) throws IOException {
|
||||
byte[] base64decodedMsg = Base64.decode(encodedString);
|
||||
return DeflateUtil.decode(base64decodedMsg);
|
||||
}
|
||||
|
@ -229,4 +231,4 @@ public class RedirectBindingUtil {
|
|||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue