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.AuthOutcome;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.common.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
|
import org.keycloak.common.util.Base64;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
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.constants.JBossSAMLURIConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
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.DocumentUtil;
|
||||||
import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
|
import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
|
||||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.keycloak.common.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Encodes and decodes to and from Base64 notation.</p>
|
* <p>Encodes and decodes to and from Base64 notation.</p>
|
||||||
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</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:
|
* Change Log:
|
||||||
* </p>
|
* </p>
|
||||||
* <ul>
|
* <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
|
* <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
|
* value 01111111, which is an invalid base 64 character but should not
|
||||||
* throw an ArrayIndexOutOfBoundsException either. Led to discovery of
|
* 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>
|
* <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
|
* <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
|
* (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
|
* 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
|
* 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,
|
* 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. */
|
/** Specify that data should be gzip-compressed in second bit. Value is two. */
|
||||||
public final static int GZIP = 2;
|
public final static int GZIP = 2;
|
||||||
|
|
||||||
/** Specify that gzipped data should <em>not</em> be automatically gunzipped. */
|
/** Specify that data should be gunzipped. */
|
||||||
public final static int DONT_GUNZIP = 4;
|
public final static int GUNZIP = 4;
|
||||||
|
|
||||||
|
|
||||||
/** Do break lines when encoding. Value is 8. */
|
/** Do break lines when encoding. Value is 8. */
|
||||||
public final static int DO_BREAK_LINES = 8;
|
public final static int DO_BREAK_LINES = 8;
|
||||||
|
@ -179,7 +184,7 @@ public class Base64
|
||||||
* in Section 4 of RFC3548:
|
* in Section 4 of RFC3548:
|
||||||
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
|
* <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,
|
* 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.
|
* was encoded using the URL- and Filename-safe dialect.
|
||||||
*/
|
*/
|
||||||
public final static int URL_SAFE = 16;
|
public final static int URL_SAFE = 16;
|
||||||
|
@ -476,7 +481,7 @@ public class Base64
|
||||||
* anywhere along their length by specifying
|
* anywhere along their length by specifying
|
||||||
* <var>srcOffset</var> and <var>destOffset</var>.
|
* <var>srcOffset</var> and <var>destOffset</var>.
|
||||||
* This method does not check to make sure your arrays
|
* 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>source</var> array or <var>destOffset</var> + 4 for
|
||||||
* the <var>destination</var> array.
|
* the <var>destination</var> array.
|
||||||
* The actual number of significant bytes in your array is
|
* 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.
|
* writing it to the <code>encoded</code> ByteBuffer.
|
||||||
* This is an experimental feature. Currently it does not
|
* This is an experimental feature. Currently it does not
|
||||||
* pass along any options (such as {@link #DO_BREAK_LINES}
|
* pass along any options (such as {@link #DO_BREAK_LINES}
|
||||||
* or {@link #GZIP}.
|
* or {@link #GZIP}).
|
||||||
*
|
*
|
||||||
* @param raw input buffer
|
* @param raw input buffer
|
||||||
* @param encoded output buffer
|
* @param encoded output buffer
|
||||||
|
@ -733,7 +738,7 @@ public class Base64
|
||||||
* Example options:<pre>
|
* Example options:<pre>
|
||||||
* GZIP: gzip-compresses object before encoding it.
|
* GZIP: gzip-compresses object before encoding it.
|
||||||
* DO_BREAK_LINES: break lines at 76 characters
|
* 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>
|
* </pre>
|
||||||
* <p>
|
* <p>
|
||||||
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
|
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
|
||||||
|
@ -1115,15 +1120,8 @@ public class Base64
|
||||||
* @return decoded data
|
* @return decoded data
|
||||||
* @since 2.3.1
|
* @since 2.3.1
|
||||||
*/
|
*/
|
||||||
public static byte[] decode( byte[] source )
|
public static byte[] decode( byte[] source ) throws java.io.IOException {
|
||||||
throws java.io.IOException {
|
return decode( source, 0, source.length, Base64.NO_OPTIONS );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1231,9 +1229,9 @@ public class Base64
|
||||||
* detecting gzip-compressed data and decompressing it.
|
* detecting gzip-compressed data and decompressing it.
|
||||||
*
|
*
|
||||||
* @param s the string to decode
|
* @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
|
* @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
|
* @throws NullPointerException if <tt>s</tt> is null
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
|
@ -1257,46 +1255,41 @@ public class Base64
|
||||||
|
|
||||||
// Check to see if it's gzip-compressed
|
// Check to see if it's gzip-compressed
|
||||||
// GZIP Magic Two-Byte Number: 0x8b1f (35615)
|
// GZIP Magic Two-Byte Number: 0x8b1f (35615)
|
||||||
boolean dontGunzip = (options & DONT_GUNZIP) != 0;
|
boolean doGunzip = (options & GUNZIP) != 0;
|
||||||
if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {
|
if( (bytes != null) && (bytes.length >= 4) && doGunzip ) {
|
||||||
|
|
||||||
int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
|
int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
|
||||||
if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) {
|
if( java.util.zip.GZIPInputStream.GZIP_MAGIC != head ) {
|
||||||
java.io.ByteArrayInputStream bais = null;
|
throw new IOException("Provided data has no GZIP magic header.");
|
||||||
java.util.zip.GZIPInputStream gzis = null;
|
}
|
||||||
java.io.ByteArrayOutputStream baos = null;
|
java.io.ByteArrayInputStream bais = null;
|
||||||
byte[] buffer = new byte[2048];
|
java.util.zip.GZIPInputStream gzis = null;
|
||||||
int length = 0;
|
java.io.ByteArrayOutputStream baos = null;
|
||||||
|
byte[] buffer = new byte[2048];
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
baos = new java.io.ByteArrayOutputStream();
|
baos = new java.io.ByteArrayOutputStream();
|
||||||
bais = new java.io.ByteArrayInputStream( bytes );
|
bais = new java.io.ByteArrayInputStream( bytes );
|
||||||
gzis = new java.util.zip.GZIPInputStream( bais );
|
gzis = new java.util.zip.GZIPInputStream( bais );
|
||||||
|
|
||||||
while( ( length = gzis.read( buffer ) ) >= 0 ) {
|
while( ( length = gzis.read( buffer ) ) >= 0 ) {
|
||||||
baos.write(buffer,0,length);
|
baos.write(buffer,0,length);
|
||||||
} // end while: reading input
|
} // end while: reading input
|
||||||
|
|
||||||
// No error? Get new bytes.
|
// No error? Get new bytes.
|
||||||
bytes = baos.toByteArray();
|
bytes = baos.toByteArray();
|
||||||
|
|
||||||
} // end try
|
} // end try
|
||||||
catch( java.io.IOException e ) {
|
catch( java.io.IOException e ) {
|
||||||
if (e.getMessage().equals("Unsupported compression method")) {
|
throw new IOException("Failed to gunzip", e);
|
||||||
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 :/
|
} // end catch
|
||||||
} else {
|
finally {
|
||||||
e.printStackTrace();
|
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
|
} // end if: bytes.length >= 2
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
|
|
|
@ -31,8 +31,7 @@ public class Base64Url {
|
||||||
public static byte[] decode(String s) {
|
public static byte[] decode(String s) {
|
||||||
s = encodeBase64UrlToBase64(s);
|
s = encodeBase64UrlToBase64(s);
|
||||||
try {
|
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);
|
||||||
return Base64.decode(s, Base64.DONT_GUNZIP);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(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;
|
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.constants.WSTrustConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.common.util.Base64;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
|
@ -201,14 +201,13 @@ public class DSAKeyValueType implements KeyValueType {
|
||||||
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
||||||
*/
|
*/
|
||||||
public DSAPublicKey convertToPublicKey() throws 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 {
|
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");
|
KeyFactory dsaKeyFactory = KeyFactory.getInstance("dsa");
|
||||||
DSAPublicKeySpec kspec = new DSAPublicKeySpec(BigY, BigP, BigQ, BigG);
|
DSAPublicKeySpec kspec = new DSAPublicKeySpec(BigY, BigP, BigQ, BigG);
|
||||||
return (DSAPublicKey) dsaKeyFactory.generatePublic(kspec);
|
return (DSAPublicKey) dsaKeyFactory.generatePublic(kspec);
|
||||||
|
@ -225,14 +224,13 @@ public class DSAKeyValueType implements KeyValueType {
|
||||||
* @throws ProcessingException
|
* @throws ProcessingException
|
||||||
*/
|
*/
|
||||||
public DSAPrivateKey convertToPrivateKey() 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 {
|
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");
|
KeyFactory dsaKeyFactory = KeyFactory.getInstance("dsa");
|
||||||
DSAPrivateKeySpec kspec = new DSAPrivateKeySpec(BigY, BigP, BigQ, BigG);
|
DSAPrivateKeySpec kspec = new DSAPrivateKeySpec(BigY, BigP, BigQ, BigG);
|
||||||
return (DSAPrivateKey) dsaKeyFactory.generatePrivate(kspec);
|
return (DSAPrivateKey) dsaKeyFactory.generatePrivate(kspec);
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
package org.keycloak.dom.xmlsec.w3.xmldsig;
|
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.constants.WSTrustConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.common.util.Base64;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
|
@ -97,10 +97,9 @@ public class RSAKeyValueType implements KeyValueType {
|
||||||
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
||||||
*/
|
*/
|
||||||
public RSAPublicKey convertToPublicKey() throws 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 {
|
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");
|
KeyFactory rsaKeyFactory = KeyFactory.getInstance("rsa");
|
||||||
RSAPublicKeySpec kspec = new RSAPublicKeySpec(bigModulus, bigEx);
|
RSAPublicKeySpec kspec = new RSAPublicKeySpec(bigModulus, bigEx);
|
||||||
return (RSAPublicKey) rsaKeyFactory.generatePublic(kspec);
|
return (RSAPublicKey) rsaKeyFactory.generatePublic(kspec);
|
||||||
|
@ -117,10 +116,9 @@ public class RSAKeyValueType implements KeyValueType {
|
||||||
* @throws ProcessingException
|
* @throws ProcessingException
|
||||||
*/
|
*/
|
||||||
public RSAPrivateKey convertToPrivateKey() 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 {
|
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");
|
KeyFactory rsaKeyFactory = KeyFactory.getInstance("rsa");
|
||||||
RSAPrivateKeySpec kspec = new RSAPrivateKeySpec(bigModulus, bigEx);
|
RSAPrivateKeySpec kspec = new RSAPrivateKeySpec(bigModulus, bigEx);
|
||||||
return (RSAPrivateKey) rsaKeyFactory.generatePrivate(kspec);
|
return (RSAPrivateKey) rsaKeyFactory.generatePrivate(kspec);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,7 +43,12 @@ public class SAMLRequestParser {
|
||||||
|
|
||||||
public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage) {
|
public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage) {
|
||||||
InputStream is;
|
InputStream is;
|
||||||
is = RedirectBindingUtil.base64DeflateDecode(samlMessage);
|
try {
|
||||||
|
is = RedirectBindingUtil.base64DeflateDecode(samlMessage);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.samlBase64DecodingError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
String message = null;
|
String message = null;
|
||||||
try {
|
try {
|
||||||
|
@ -105,7 +110,13 @@ public class SAMLRequestParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SAMLDocumentHolder parseResponseRedirectBinding(String samlMessage) {
|
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()) {
|
if (log.isDebugEnabled()) {
|
||||||
String message = null;
|
String message = null;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.processing.core.saml.v2.util;
|
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.DSAKeyValueType;
|
||||||
import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
|
import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
|
||||||
import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
|
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.PicketLinkLoggerFactory;
|
||||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLConstants;
|
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.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 org.xml.sax.SAXException;
|
||||||
|
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.processing.core.util;
|
package org.keycloak.saml.processing.core.util;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Base64;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
|
import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
|
||||||
import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
|
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.constants.WSTrustConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
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.common.util.Base64;
|
|
||||||
import org.keycloak.saml.common.util.DocumentUtil;
|
import org.keycloak.saml.common.util.DocumentUtil;
|
||||||
import org.keycloak.saml.common.util.StringUtil;
|
import org.keycloak.saml.common.util.StringUtil;
|
||||||
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
import org.keycloak.saml.common.util.SystemPropertiesUtil;
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.processing.web.util;
|
package org.keycloak.saml.processing.web.util;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Base64;
|
||||||
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.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.util.Base64;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -43,7 +43,7 @@ public class PostBindingUtil {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String base64Encode(String stringToEncode) throws IOException {
|
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)
|
if (encodedString == null)
|
||||||
throw logger.nullArgumentError("encodedString");
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.saml.processing.web.util;
|
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.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.util.Base64;
|
|
||||||
import org.keycloak.saml.common.util.StringUtil;
|
import org.keycloak.saml.common.util.StringUtil;
|
||||||
import org.keycloak.saml.processing.api.util.DeflateUtil;
|
import org.keycloak.saml.processing.api.util.DeflateUtil;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ public class RedirectBindingUtil {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static String base64Encode(byte[] stringToEncode) 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
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static String base64URLEncode(byte[] stringToEncode) 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);
|
return urlEncode(base64Request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ public class RedirectBindingUtil {
|
||||||
*/
|
*/
|
||||||
public static String deflateBase64Encode(byte[] stringToEncode) throws IOException {
|
public static String deflateBase64Encode(byte[] stringToEncode) throws IOException {
|
||||||
byte[] deflatedMsg = DeflateUtil.encode(stringToEncode);
|
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
|
* @param encodedString
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static InputStream base64DeflateDecode(String encodedString) {
|
public static InputStream base64DeflateDecode(String encodedString) throws IOException {
|
||||||
byte[] base64decodedMsg = Base64.decode(encodedString);
|
byte[] base64decodedMsg = Base64.decode(encodedString);
|
||||||
return DeflateUtil.decode(base64decodedMsg);
|
return DeflateUtil.decode(base64decodedMsg);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue