KEYCLOAK-3971 Explicitly set encoding for SAML message processing

This commit is contained in:
Hynek Mlnarik 2016-12-15 14:01:25 +01:00
parent 3c2a12d019
commit 7d51df4eed
23 changed files with 229 additions and 83 deletions

View file

@ -40,7 +40,7 @@ public class SamlUtil {
httpFacade.getResponse().setHeader("Content-Type", "text/html"); httpFacade.getResponse().setHeader("Content-Type", "text/html");
httpFacade.getResponse().setHeader("Pragma", "no-cache"); httpFacade.getResponse().setHeader("Pragma", "no-cache");
httpFacade.getResponse().setHeader("Cache-Control", "no-cache, no-store"); httpFacade.getResponse().setHeader("Cache-Control", "no-cache, no-store");
httpFacade.getResponse().getOutputStream().write(html.getBytes()); httpFacade.getResponse().getOutputStream().write(html.getBytes(GeneralConstants.SAML_CHARSET));
httpFacade.getResponse().end(); httpFacade.getResponse().end();
} else { } else {
String uri = asRequest ? binding.redirectBinding(document).requestURI(actionUrl).toString() : binding.redirectBinding(document).responseURI(actionUrl).toString(); String uri = asRequest ? binding.redirectBinding(document).requestURI(actionUrl).toString() : binding.redirectBinding(document).responseURI(actionUrl).toString();

View file

@ -21,6 +21,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -28,18 +29,41 @@ import java.io.InputStreamReader;
*/ */
public final class StreamUtil { public final class StreamUtil {
private static final int BUFFER_LENGTH = 4096;
private StreamUtil() { private StreamUtil() {
} }
/**
* Reads string from byte input stream.
* @param in InputStream to build the String from
* @return String representation of the input stream contents decoded using default charset
* @throws IOException
* @deprecated Use {@link #readString(java.io.InputStream, java.nio.charset.Charset)} variant.
*/
@Deprecated
public static String readString(InputStream in) throws IOException public static String readString(InputStream in) throws IOException
{ {
char[] buffer = new char[1024]; return readString(in, Charset.defaultCharset());
}
/**
* Reads string from byte input stream.
* @param in InputStream to build the String from
* @param charset Charset used to decode the input stream
* @return String representation of the input stream contents decoded using given charset
* @throws IOException
* @deprecated Use {@link #readString(java.io.InputStream, java.nio.charset.Charset)} variant.
*/
public static String readString(InputStream in, Charset charset) throws IOException
{
char[] buffer = new char[BUFFER_LENGTH];
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(in)); BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset));
int wasRead; int wasRead;
do do
{ {
wasRead = reader.read(buffer, 0, 1024); wasRead = reader.read(buffer, 0, BUFFER_LENGTH);
if (wasRead > 0) if (wasRead > 0)
{ {
builder.append(buffer, 0, wasRead); builder.append(buffer, 0, wasRead);

View file

@ -16,6 +16,7 @@
*/ */
package org.keycloak.saml.common.constants; package org.keycloak.saml.common.constants;
import java.nio.charset.Charset;
/** /**
* Constants * Constants
@ -147,4 +148,7 @@ public interface GeneralConstants {
String BASE64_ENCODE_WSTRUST_SECRET_KEY = "picketlink.wstrust.base64_encode_wstrust_secret_key"; String BASE64_ENCODE_WSTRUST_SECRET_KEY = "picketlink.wstrust.base64_encode_wstrust_secret_key";
String HTTP_HEADER_X_REQUESTED_WITH = "X-Requested-With"; String HTTP_HEADER_X_REQUESTED_WITH = "X-Requested-With";
public static final String SAML_CHARSET_NAME = System.getProperty("keycloak.saml.saml_message_charset", "UTF-8");
public static final Charset SAML_CHARSET = Charset.forName(SAML_CHARSET_NAME);
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.saml; package org.keycloak.saml;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.KeycloakUriBuilder; import org.keycloak.common.util.KeycloakUriBuilder;
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;
@ -29,6 +30,7 @@ import org.keycloak.saml.processing.core.saml.v2.util.DocumentUtil;
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil; import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
import org.keycloak.saml.processing.web.util.PostBindingUtil; import org.keycloak.saml.processing.web.util.PostBindingUtil;
import org.keycloak.saml.processing.web.util.RedirectBindingUtil; import org.keycloak.saml.processing.web.util.RedirectBindingUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@ -38,7 +40,6 @@ import javax.crypto.spec.SecretKeySpec;
import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.KeyPair; import java.security.KeyPair;
@ -155,8 +156,8 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
} }
public String encoded() throws ProcessingException, ConfigurationException, IOException { public String encoded() throws ProcessingException, ConfigurationException, IOException {
byte[] responseBytes = DocumentUtil.getDocumentAsString(document).getBytes("UTF-8"); byte[] responseBytes = DocumentUtil.getDocumentAsString(document).getBytes(GeneralConstants.SAML_CHARSET);
return PostBindingUtil.base64Encode(new String(responseBytes)); return PostBindingUtil.base64Encode(new String(responseBytes, GeneralConstants.SAML_CHARSET));
} }
public Document getDocument() { public Document getDocument() {
return document; return document;
@ -300,8 +301,8 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
public String buildHtmlPostResponse(Document responseDoc, String actionUrl, boolean asRequest) throws ProcessingException, ConfigurationException, IOException { public String buildHtmlPostResponse(Document responseDoc, String actionUrl, boolean asRequest) throws ProcessingException, ConfigurationException, IOException {
byte[] responseBytes = org.keycloak.saml.common.util.DocumentUtil.getDocumentAsString(responseDoc).getBytes("UTF-8"); byte[] responseBytes = org.keycloak.saml.common.util.DocumentUtil.getDocumentAsString(responseDoc).getBytes(GeneralConstants.SAML_CHARSET);
String samlResponse = PostBindingUtil.base64Encode(new String(responseBytes)); String samlResponse = PostBindingUtil.base64Encode(new String(responseBytes, GeneralConstants.SAML_CHARSET));
return buildHtml(samlResponse, actionUrl, asRequest); return buildHtml(samlResponse, actionUrl, asRequest);
} }
@ -315,26 +316,26 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
key = GeneralConstants.SAML_REQUEST_KEY; key = GeneralConstants.SAML_REQUEST_KEY;
} }
builder.append("<HTML>"); builder.append("<HTML>")
builder.append("<HEAD>"); .append("<HEAD>")
builder.append("<TITLE>SAML HTTP Post Binding</TITLE>"); .append("<TITLE>SAML HTTP Post Binding</TITLE>")
builder.append("</HEAD>"); .append("</HEAD>")
builder.append("<BODY Onload=\"document.forms[0].submit()\">"); .append("<BODY Onload=\"document.forms[0].submit()\">")
builder.append("<FORM METHOD=\"POST\" ACTION=\"" + actionUrl + "\">"); .append("<FORM METHOD=\"POST\" ACTION=\"").append(actionUrl).append("\">")
builder.append("<INPUT TYPE=\"HIDDEN\" NAME=\"" + key + "\"" + " VALUE=\"" + samlResponse + "\"/>"); .append("<INPUT TYPE=\"HIDDEN\" NAME=\"").append(key).append("\"").append(" VALUE=\"").append(samlResponse).append("\"/>");
if (isNotNull(relayState)) { if (isNotNull(relayState)) {
builder.append("<INPUT TYPE=\"HIDDEN\" NAME=\"RelayState\" " + "VALUE=\"" + escapeAttribute(relayState) + "\"/>"); builder.append("<INPUT TYPE=\"HIDDEN\" NAME=\"RelayState\" " + "VALUE=\"").append(escapeAttribute(relayState)).append("\"/>");
} }
builder.append("<NOSCRIPT>"); builder.append("<NOSCRIPT>")
builder.append("<P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.</P>"); .append("<P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.</P>")
builder.append("<INPUT TYPE=\"SUBMIT\" VALUE=\"CONTINUE\" />"); .append("<INPUT TYPE=\"SUBMIT\" VALUE=\"CONTINUE\" />")
builder.append("</NOSCRIPT>"); .append("</NOSCRIPT>")
builder.append("</FORM></BODY></HTML>"); .append("</FORM></BODY></HTML>");
return builder.toString(); return builder.toString();
} }
@ -342,7 +343,7 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
public String base64Encoded(Document document) throws ConfigurationException, ProcessingException, IOException { public String base64Encoded(Document document) throws ConfigurationException, ProcessingException, IOException {
String documentAsString = DocumentUtil.getDocumentAsString(document); String documentAsString = DocumentUtil.getDocumentAsString(document);
logger.debugv("saml document: {0}", documentAsString); logger.debugv("saml document: {0}", documentAsString);
byte[] responseBytes = documentAsString.getBytes("UTF-8"); byte[] responseBytes = documentAsString.getBytes(GeneralConstants.SAML_CHARSET);
return RedirectBindingUtil.deflateBase64URLEncode(responseBytes); return RedirectBindingUtil.deflateBase64URLEncode(responseBytes);
} }
@ -364,9 +365,9 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
byte[] sig = new byte[0]; byte[] sig = new byte[0];
try { try {
signature.initSign(signingKeyPair.getPrivate()); signature.initSign(signingKeyPair.getPrivate());
signature.update(rawQuery.getBytes("UTF-8")); signature.update(rawQuery.getBytes(GeneralConstants.SAML_CHARSET));
sig = signature.sign(); sig = signature.sign();
} catch (InvalidKeyException | UnsupportedEncodingException | SignatureException e) { } catch (InvalidKeyException | SignatureException e) {
throw new ProcessingException(e); throw new ProcessingException(e);
} }
String encodedSig = RedirectBindingUtil.base64URLEncode(sig); String encodedSig = RedirectBindingUtil.base64URLEncode(sig);

View file

@ -18,9 +18,11 @@
package org.keycloak.saml; package org.keycloak.saml;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.StreamUtil; import org.keycloak.common.util.StreamUtil;
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.processing.api.saml.v2.request.SAML2Request; 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.saml.v2.response.SAML2Response;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
@ -45,13 +47,13 @@ public class SAMLRequestParser {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
String message = null; String message = null;
try { try {
message = StreamUtil.readString(is); message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
log.debug("SAML Redirect Binding"); log.debug("SAML Redirect Binding");
log.debug(message); log.debug(message);
is = new ByteArrayInputStream(message.getBytes()); is = new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET));
} }
SAML2Request saml2Request = new SAML2Request(); SAML2Request saml2Request = new SAML2Request();
@ -69,7 +71,7 @@ public class SAMLRequestParser {
InputStream is; InputStream is;
byte[] samlBytes = PostBindingUtil.base64Decode(samlMessage); byte[] samlBytes = PostBindingUtil.base64Decode(samlMessage);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
String str = new String(samlBytes); String str = new String(samlBytes, GeneralConstants.SAML_CHARSET);
log.debug("SAML POST Binding"); log.debug("SAML POST Binding");
log.debug(str); log.debug(str);
} }
@ -92,7 +94,7 @@ public class SAMLRequestParser {
public static SAMLDocumentHolder parseResponseDocument(byte[] samlBytes) { public static SAMLDocumentHolder parseResponseDocument(byte[] samlBytes) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
String str = new String(samlBytes); String str = new String(samlBytes, GeneralConstants.SAML_CHARSET);
log.debug(str); log.debug(str);
} }
InputStream is = new ByteArrayInputStream(samlBytes); InputStream is = new ByteArrayInputStream(samlBytes);
@ -111,13 +113,13 @@ public class SAMLRequestParser {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
String message = null; String message = null;
try { try {
message = StreamUtil.readString(is); message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
log.debug("SAML Redirect Binding"); log.debug("SAML Redirect Binding");
log.debug(message); log.debug(message);
is = new ByteArrayInputStream(message.getBytes()); is = new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET));
} }
SAML2Response response = new SAML2Response(); SAML2Response response = new SAML2Response();

View file

@ -376,7 +376,7 @@ public class DocumentUtil {
throw logger.processingError(e); throw logger.processingError(e);
} }
return new String(baos.toByteArray()); return new String(baos.toByteArray(), GeneralConstants.SAML_CHARSET);
} }
/** /**

View file

@ -75,7 +75,7 @@ public class StaxUtil {
public static XMLEventWriter getXMLEventWriter(final OutputStream outStream) throws ProcessingException { public static XMLEventWriter getXMLEventWriter(final OutputStream outStream) throws ProcessingException {
XMLOutputFactory xmlOutputFactory = getXMLOutputFactory(); XMLOutputFactory xmlOutputFactory = getXMLOutputFactory();
try { try {
return xmlOutputFactory.createXMLEventWriter(outStream, "UTF-8"); return xmlOutputFactory.createXMLEventWriter(outStream, GeneralConstants.SAML_CHARSET_NAME);
} catch (XMLStreamException e) { } catch (XMLStreamException e) {
throw logger.processingError(e); throw logger.processingError(e);
} }
@ -93,7 +93,7 @@ public class StaxUtil {
public static XMLStreamWriter getXMLStreamWriter(final OutputStream outStream) throws ProcessingException { public static XMLStreamWriter getXMLStreamWriter(final OutputStream outStream) throws ProcessingException {
XMLOutputFactory xmlOutputFactory = getXMLOutputFactory(); XMLOutputFactory xmlOutputFactory = getXMLOutputFactory();
try { try {
return xmlOutputFactory.createXMLStreamWriter(outStream, "UTF-8"); return xmlOutputFactory.createXMLStreamWriter(outStream, GeneralConstants.SAML_CHARSET_NAME);
} catch (XMLStreamException e) { } catch (XMLStreamException e) {
throw logger.processingError(e); throw logger.processingError(e);
} }

View file

@ -25,6 +25,7 @@ import org.keycloak.dom.saml.v2.protocol.RequestAbstractType;
import org.keycloak.dom.saml.v2.protocol.ResponseType; import org.keycloak.dom.saml.v2.protocol.ResponseType;
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.JBossSAMLConstants; 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;
@ -39,6 +40,7 @@ import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.keycloak.saml.processing.core.saml.v2.writers.SAMLRequestWriter; import org.keycloak.saml.processing.core.saml.v2.writers.SAMLRequestWriter;
import org.keycloak.saml.processing.core.saml.v2.writers.SAMLResponseWriter; import org.keycloak.saml.processing.core.saml.v2.writers.SAMLResponseWriter;
import org.keycloak.saml.processing.core.util.JAXPValidationUtil; import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.datatype.XMLGregorianCalendar;
@ -274,7 +276,7 @@ public class SAML2Request {
writer.write((LogoutRequestType) rat); writer.write((LogoutRequestType) rat);
} }
return DocumentUtil.getDocument(new String(bos.toByteArray())); return DocumentUtil.getDocument(new String(bos.toByteArray(), GeneralConstants.SAML_CHARSET));
} }
/** /**

View file

@ -16,6 +16,8 @@
*/ */
package org.keycloak.saml.processing.api.util; package org.keycloak.saml.processing.api.util;
import org.keycloak.saml.common.constants.GeneralConstants;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@ -62,7 +64,7 @@ public class DeflateUtil {
* @throws IOException * @throws IOException
*/ */
public static byte[] encode(String message) throws IOException { public static byte[] encode(String message) throws IOException {
return encode(message.getBytes()); return encode(message.getBytes(GeneralConstants.SAML_CHARSET));
} }
/** /**

View file

@ -37,6 +37,7 @@ import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
import org.keycloak.dom.xmlsec.w3.xmlenc.EncryptionMethodType; import org.keycloak.dom.xmlsec.w3.xmlenc.EncryptionMethodType;
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.JBossSAMLConstants; 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.ParsingException; import org.keycloak.saml.common.exceptions.ParsingException;
@ -44,6 +45,7 @@ import org.keycloak.saml.common.parsers.ParserNamespaceSupport;
import org.keycloak.saml.common.util.StaxParserUtil; import org.keycloak.saml.common.util.StaxParserUtil;
import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil; import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil; import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
@ -476,7 +478,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
keySize = BigInteger.valueOf(Long.valueOf(StaxParserUtil.getElementText(xmlEventReader))); keySize = BigInteger.valueOf(Long.valueOf(StaxParserUtil.getElementText(xmlEventReader)));
} else if ("OAEPparams".equals(localPart)) { } else if ("OAEPparams".equals(localPart)) {
startElement = StaxParserUtil.getNextStartElement(xmlEventReader); startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
OAEPparams = StaxParserUtil.getElementText(xmlEventReader).getBytes(); OAEPparams = StaxParserUtil.getElementText(xmlEventReader).getBytes(GeneralConstants.SAML_CHARSET);
} else { } else {
throw logger.parserUnknownTag(localPart, startElement.getLocation()); throw logger.parserUnknownTag(localPart, startElement.getLocation());
} }

View file

@ -41,6 +41,7 @@ import org.keycloak.dom.xmlsec.w3.xmldsig.X509CertificateType;
import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType; import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType;
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.JBossSAMLConstants; 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.constants.WSTrustConstants; import org.keycloak.saml.common.constants.WSTrustConstants;
@ -50,6 +51,7 @@ import org.keycloak.saml.processing.core.parsers.saml.SAML11SubjectParser;
import org.keycloak.saml.processing.core.saml.v1.SAML11Constants; import org.keycloak.saml.processing.core.saml.v1.SAML11Constants;
import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil; import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil;
import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil; import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
@ -561,7 +563,7 @@ public class SAML11ParserUtil {
X509CertificateType cert = new X509CertificateType(); X509CertificateType cert = new X509CertificateType();
String certValue = StaxParserUtil.getElementText(xmlEventReader); String certValue = StaxParserUtil.getElementText(xmlEventReader);
cert.setEncodedCertificate(certValue.getBytes()); cert.setEncodedCertificate(certValue.getBytes(GeneralConstants.SAML_CHARSET));
x509.add(cert); x509.add(cert);
EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader); EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
@ -614,11 +616,11 @@ public class SAML11ParserUtil {
if (tag.equals(WSTrustConstants.XMLDSig.MODULUS)) { if (tag.equals(WSTrustConstants.XMLDSig.MODULUS)) {
startElement = StaxParserUtil.getNextStartElement(xmlEventReader); startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
String text = StaxParserUtil.getElementText(xmlEventReader); String text = StaxParserUtil.getElementText(xmlEventReader);
rsaKeyValue.setModulus(text.getBytes()); rsaKeyValue.setModulus(text.getBytes(GeneralConstants.SAML_CHARSET));
} else if (tag.equals(WSTrustConstants.XMLDSig.EXPONENT)) { } else if (tag.equals(WSTrustConstants.XMLDSig.EXPONENT)) {
startElement = StaxParserUtil.getNextStartElement(xmlEventReader); startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
String text = StaxParserUtil.getElementText(xmlEventReader); String text = StaxParserUtil.getElementText(xmlEventReader);
rsaKeyValue.setExponent(text.getBytes()); rsaKeyValue.setExponent(text.getBytes(GeneralConstants.SAML_CHARSET));
} else } else
throw logger.parserUnknownTag(tag, startElement.getLocation()); throw logger.parserUnknownTag(tag, startElement.getLocation());
} }

View file

@ -34,6 +34,7 @@ import org.keycloak.dom.xmlsec.w3.xmldsig.X509CertificateType;
import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType; import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType;
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.JBossSAMLConstants; 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.constants.WSTrustConstants; import org.keycloak.saml.common.constants.WSTrustConstants;
@ -42,6 +43,7 @@ import org.keycloak.saml.common.util.StaxParserUtil;
import org.keycloak.saml.common.util.StringUtil; import org.keycloak.saml.common.util.StringUtil;
import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil; import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil;
import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil; import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.datatype.XMLGregorianCalendar;
@ -98,7 +100,7 @@ public class SAMLParserUtil {
X509CertificateType cert = new X509CertificateType(); X509CertificateType cert = new X509CertificateType();
String certValue = StaxParserUtil.getElementText(xmlEventReader); String certValue = StaxParserUtil.getElementText(xmlEventReader);
cert.setEncodedCertificate(certValue.getBytes()); cert.setEncodedCertificate(certValue.getBytes(GeneralConstants.SAML_CHARSET));
x509.add(cert); x509.add(cert);
EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader); EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
@ -151,11 +153,11 @@ public class SAMLParserUtil {
if (tag.equals(WSTrustConstants.XMLDSig.MODULUS)) { if (tag.equals(WSTrustConstants.XMLDSig.MODULUS)) {
startElement = StaxParserUtil.getNextStartElement(xmlEventReader); startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
String text = StaxParserUtil.getElementText(xmlEventReader); String text = StaxParserUtil.getElementText(xmlEventReader);
rsaKeyValue.setModulus(text.getBytes()); rsaKeyValue.setModulus(text.getBytes(GeneralConstants.SAML_CHARSET));
} else if (tag.equals(WSTrustConstants.XMLDSig.EXPONENT)) { } else if (tag.equals(WSTrustConstants.XMLDSig.EXPONENT)) {
startElement = StaxParserUtil.getNextStartElement(xmlEventReader); startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
String text = StaxParserUtil.getElementText(xmlEventReader); String text = StaxParserUtil.getElementText(xmlEventReader);
rsaKeyValue.setExponent(text.getBytes()); rsaKeyValue.setExponent(text.getBytes(GeneralConstants.SAML_CHARSET));
} else } else
throw logger.parserUnknownTag(tag, startElement.getLocation()); throw logger.parserUnknownTag(tag, startElement.getLocation());
} }

View file

@ -49,6 +49,7 @@ import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
import org.keycloak.saml.processing.core.saml.v2.writers.SAMLAssertionWriter; import org.keycloak.saml.processing.core.saml.v2.writers.SAMLAssertionWriter;
import org.keycloak.saml.processing.core.util.JAXPValidationUtil; import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil; import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@ -62,7 +63,9 @@ import java.security.PublicKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.keycloak.rotation.HardcodedKeyLocator; import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.saml.common.constants.GeneralConstants;
/** /**
* Utility to deal with assertions * Utility to deal with assertions
@ -87,7 +90,7 @@ public class AssertionUtil {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
SAMLAssertionWriter writer = new SAMLAssertionWriter(StaxUtil.getXMLStreamWriter(baos)); SAMLAssertionWriter writer = new SAMLAssertionWriter(StaxUtil.getXMLStreamWriter(baos));
writer.write(assertion); writer.write(assertion);
return new String(baos.toByteArray()); return new String(baos.toByteArray(), GeneralConstants.SAML_CHARSET);
} }
/** /**

View file

@ -22,11 +22,13 @@ import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
import org.keycloak.dom.xmlsec.w3.xmldsig.SignatureType; import org.keycloak.dom.xmlsec.w3.xmldsig.SignatureType;
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.JBossSAMLConstants; 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.util.Base64; 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.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@ -106,7 +108,7 @@ public class SignatureUtil {
String algo = signingKey.getAlgorithm(); String algo = signingKey.getAlgorithm();
Signature sig = getSignature(algo); Signature sig = getSignature(algo);
sig.initSign(signingKey); sig.initSign(signingKey);
sig.update(stringToBeSigned.getBytes()); sig.update(stringToBeSigned.getBytes(GeneralConstants.SAML_CHARSET));
return sig.sign(); return sig.sign();
} }
@ -191,7 +193,7 @@ public class SignatureUtil {
Element childElement = (Element) node; Element childElement = (Element) node;
String tag = childElement.getLocalName(); String tag = childElement.getLocalName();
byte[] text = childElement.getTextContent().getBytes(); byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
if (WSTrustConstants.XMLDSig.P.equals(tag)) { if (WSTrustConstants.XMLDSig.P.equals(tag)) {
dsa.setP(text); dsa.setP(text);
@ -232,7 +234,7 @@ public class SignatureUtil {
Element childElement = (Element) node; Element childElement = (Element) node;
String tag = childElement.getLocalName(); String tag = childElement.getLocalName();
byte[] text = childElement.getTextContent().getBytes(); byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
if (WSTrustConstants.XMLDSig.MODULUS.equals(tag)) { if (WSTrustConstants.XMLDSig.MODULUS.equals(tag)) {
rsa.setModulus(text); rsa.setModulus(text);
@ -262,8 +264,8 @@ public class SignatureUtil {
byte[] exponent = pubKey.getPublicExponent().toByteArray(); byte[] exponent = pubKey.getPublicExponent().toByteArray();
RSAKeyValueType rsaKeyValue = new RSAKeyValueType(); RSAKeyValueType rsaKeyValue = new RSAKeyValueType();
rsaKeyValue.setModulus(Base64.encodeBytes(modulus).getBytes()); rsaKeyValue.setModulus(Base64.encodeBytes(modulus).getBytes(GeneralConstants.SAML_CHARSET));
rsaKeyValue.setExponent(Base64.encodeBytes(exponent).getBytes()); rsaKeyValue.setExponent(Base64.encodeBytes(exponent).getBytes(GeneralConstants.SAML_CHARSET));
return rsaKeyValue; return rsaKeyValue;
} else if (key instanceof DSAPublicKey) { } else if (key instanceof DSAPublicKey) {
DSAPublicKey pubKey = (DSAPublicKey) key; DSAPublicKey pubKey = (DSAPublicKey) key;
@ -273,10 +275,10 @@ public class SignatureUtil {
byte[] Y = pubKey.getY().toByteArray(); byte[] Y = pubKey.getY().toByteArray();
DSAKeyValueType dsaKeyValue = new DSAKeyValueType(); DSAKeyValueType dsaKeyValue = new DSAKeyValueType();
dsaKeyValue.setP(Base64.encodeBytes(P).getBytes()); dsaKeyValue.setP(Base64.encodeBytes(P).getBytes(GeneralConstants.SAML_CHARSET));
dsaKeyValue.setQ(Base64.encodeBytes(Q).getBytes()); dsaKeyValue.setQ(Base64.encodeBytes(Q).getBytes(GeneralConstants.SAML_CHARSET));
dsaKeyValue.setG(Base64.encodeBytes(G).getBytes()); dsaKeyValue.setG(Base64.encodeBytes(G).getBytes(GeneralConstants.SAML_CHARSET));
dsaKeyValue.setY(Base64.encodeBytes(Y).getBytes()); dsaKeyValue.setY(Base64.encodeBytes(Y).getBytes(GeneralConstants.SAML_CHARSET));
return dsaKeyValue; return dsaKeyValue;
} }
throw logger.unsupportedType(key.toString()); throw logger.unsupportedType(key.toString());

View file

@ -27,9 +27,11 @@ import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType;
import org.keycloak.saml.common.ErrorCodes; import org.keycloak.saml.common.ErrorCodes;
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.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.StaxUtil; import org.keycloak.saml.common.util.StaxUtil;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLStreamWriter;
@ -77,7 +79,7 @@ public class StaxWriterUtil {
X509CertificateType cert = (X509CertificateType) obj; X509CertificateType cert = (X509CertificateType) obj;
StaxUtil.writeStartElement(writer, WSTrustConstants.XMLDSig.DSIG_PREFIX, WSTrustConstants.XMLDSig.X509CERT, StaxUtil.writeStartElement(writer, WSTrustConstants.XMLDSig.DSIG_PREFIX, WSTrustConstants.XMLDSig.X509CERT,
WSTrustConstants.XMLDSig.DSIG_NS); WSTrustConstants.XMLDSig.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(cert.getEncodedCertificate())); StaxUtil.writeCharacters(writer, new String(cert.getEncodedCertificate(), GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
@ -105,13 +107,13 @@ public class StaxWriterUtil {
// write the rsa key modulus. // write the rsa key modulus.
byte[] modulus = type.getModulus(); byte[] modulus = type.getModulus();
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.MODULUS, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.MODULUS, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(modulus)); StaxUtil.writeCharacters(writer, new String(modulus, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
// write the rsa key exponent. // write the rsa key exponent.
byte[] exponent = type.getExponent(); byte[] exponent = type.getExponent();
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.EXPONENT, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.EXPONENT, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(exponent)); StaxUtil.writeCharacters(writer, new String(exponent, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
@ -126,37 +128,37 @@ public class StaxWriterUtil {
byte[] p = type.getP(); byte[] p = type.getP();
if (p != null) { if (p != null) {
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.P, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.P, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(p)); StaxUtil.writeCharacters(writer, new String(p, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }
byte[] q = type.getQ(); byte[] q = type.getQ();
if (q != null) { if (q != null) {
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.Q, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.Q, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(q)); StaxUtil.writeCharacters(writer, new String(q, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }
byte[] g = type.getG(); byte[] g = type.getG();
if (g != null) { if (g != null) {
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.G, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.G, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(g)); StaxUtil.writeCharacters(writer, new String(g, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }
byte[] y = type.getY(); byte[] y = type.getY();
if (y != null) { if (y != null) {
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.Y, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.Y, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(y)); StaxUtil.writeCharacters(writer, new String(y, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }
byte[] seed = type.getSeed(); byte[] seed = type.getSeed();
if (seed != null) { if (seed != null) {
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.SEED, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.SEED, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(seed)); StaxUtil.writeCharacters(writer, new String(seed, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }
byte[] pgen = type.getPgenCounter(); byte[] pgen = type.getPgenCounter();
if (pgen != null) { if (pgen != null) {
StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.PGEN_COUNTER, WSTrustConstants.DSIG_NS); StaxUtil.writeStartElement(writer, prefix, WSTrustConstants.XMLDSig.PGEN_COUNTER, WSTrustConstants.DSIG_NS);
StaxUtil.writeCharacters(writer, new String(pgen)); StaxUtil.writeCharacters(writer, new String(pgen, GeneralConstants.SAML_CHARSET));
StaxUtil.writeEndElement(writer); StaxUtil.writeEndElement(writer);
} }

View file

@ -18,6 +18,8 @@ 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.constants.GeneralConstants;
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;
@ -89,7 +91,7 @@ public class JAXBUtil {
JAXBContext jc = getJAXBContext(pkgName); JAXBContext jc = getJAXBContext(pkgName);
Marshaller marshaller = jc.createMarshaller(); Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); marshaller.setProperty(Marshaller.JAXB_ENCODING, GeneralConstants.SAML_CHARSET_NAME);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE); // Breaks signatures marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE); // Breaks signatures
return marshaller; return marshaller;
} }

View file

@ -22,6 +22,7 @@ import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
import org.keycloak.dom.xmlsec.w3.xmldsig.SignatureType; import org.keycloak.dom.xmlsec.w3.xmldsig.SignatureType;
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.JBossSAMLConstants; 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;
@ -572,7 +573,7 @@ public class XMLSignatureUtil {
try { try {
CertificateFactory cf = CertificateFactory.getInstance("X.509"); CertificateFactory cf = CertificateFactory.getInstance("X.509");
ByteArrayInputStream bais = new ByteArrayInputStream(derFormattedString.getBytes()); ByteArrayInputStream bais = new ByteArrayInputStream(derFormattedString.getBytes(GeneralConstants.SAML_CHARSET));
while (bais.available() > 0) { while (bais.available() > 0) {
cert = (X509Certificate) cf.generateCertificate(bais); cert = (X509Certificate) cf.generateCertificate(bais);
@ -603,7 +604,7 @@ public class XMLSignatureUtil {
Element childElement = (Element) node; Element childElement = (Element) node;
String tag = childElement.getLocalName(); String tag = childElement.getLocalName();
byte[] text = childElement.getTextContent().getBytes(); byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
if (WSTrustConstants.XMLDSig.P.equals(tag)) { if (WSTrustConstants.XMLDSig.P.equals(tag)) {
dsa.setP(text); dsa.setP(text);
@ -644,7 +645,7 @@ public class XMLSignatureUtil {
Element childElement = (Element) node; Element childElement = (Element) node;
String tag = childElement.getLocalName(); String tag = childElement.getLocalName();
byte[] text = childElement.getTextContent().getBytes(); byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
if (WSTrustConstants.XMLDSig.MODULUS.equals(tag)) { if (WSTrustConstants.XMLDSig.MODULUS.equals(tag)) {
rsa.setModulus(text); rsa.setModulus(text);
@ -674,8 +675,8 @@ public class XMLSignatureUtil {
byte[] exponent = pubKey.getPublicExponent().toByteArray(); byte[] exponent = pubKey.getPublicExponent().toByteArray();
RSAKeyValueType rsaKeyValue = new RSAKeyValueType(); RSAKeyValueType rsaKeyValue = new RSAKeyValueType();
rsaKeyValue.setModulus(Base64.encodeBytes(modulus).getBytes()); rsaKeyValue.setModulus(Base64.encodeBytes(modulus).getBytes(GeneralConstants.SAML_CHARSET));
rsaKeyValue.setExponent(Base64.encodeBytes(exponent).getBytes()); rsaKeyValue.setExponent(Base64.encodeBytes(exponent).getBytes(GeneralConstants.SAML_CHARSET));
return rsaKeyValue; return rsaKeyValue;
} else if (key instanceof DSAPublicKey) { } else if (key instanceof DSAPublicKey) {
DSAPublicKey pubKey = (DSAPublicKey) key; DSAPublicKey pubKey = (DSAPublicKey) key;
@ -685,10 +686,10 @@ public class XMLSignatureUtil {
byte[] Y = pubKey.getY().toByteArray(); byte[] Y = pubKey.getY().toByteArray();
DSAKeyValueType dsaKeyValue = new DSAKeyValueType(); DSAKeyValueType dsaKeyValue = new DSAKeyValueType();
dsaKeyValue.setP(Base64.encodeBytes(P).getBytes()); dsaKeyValue.setP(Base64.encodeBytes(P).getBytes(GeneralConstants.SAML_CHARSET));
dsaKeyValue.setQ(Base64.encodeBytes(Q).getBytes()); dsaKeyValue.setQ(Base64.encodeBytes(Q).getBytes(GeneralConstants.SAML_CHARSET));
dsaKeyValue.setG(Base64.encodeBytes(G).getBytes()); dsaKeyValue.setG(Base64.encodeBytes(G).getBytes(GeneralConstants.SAML_CHARSET));
dsaKeyValue.setY(Base64.encodeBytes(Y).getBytes()); dsaKeyValue.setY(Base64.encodeBytes(Y).getBytes(GeneralConstants.SAML_CHARSET));
return dsaKeyValue; return dsaKeyValue;
} }
throw logger.unsupportedType(key.toString()); throw logger.unsupportedType(key.toString());

View file

@ -18,6 +18,7 @@ package org.keycloak.saml.processing.web.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.constants.GeneralConstants;
import org.keycloak.saml.common.util.Base64; import org.keycloak.saml.common.util.Base64;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -42,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("UTF-8"), Base64.DONT_BREAK_LINES); return Base64.encodeBytes(stringToEncode.getBytes(GeneralConstants.SAML_CHARSET), Base64.DONT_BREAK_LINES);
} }
/** /**

View file

@ -79,7 +79,7 @@ public class RedirectBindingSignatureUtil {
String urlEncodedRelayState = null; String urlEncodedRelayState = null;
if (isNotNull(relayState)) if (isNotNull(relayState))
urlEncodedRelayState = URLEncoder.encode(relayState, "UTF-8"); urlEncodedRelayState = URLEncoder.encode(relayState, GeneralConstants.SAML_CHARSET_NAME);
byte[] sigValue = computeSignature(GeneralConstants.SAML_REQUEST_KEY, urlEncodedRequest, urlEncodedRelayState, byte[] sigValue = computeSignature(GeneralConstants.SAML_REQUEST_KEY, urlEncodedRequest, urlEncodedRelayState,
signingKey); signingKey);
@ -113,7 +113,7 @@ public class RedirectBindingSignatureUtil {
String urlEncodedRelayState = null; String urlEncodedRelayState = null;
if (isNotNull(relayState)) if (isNotNull(relayState))
urlEncodedRelayState = URLEncoder.encode(relayState, "UTF-8"); urlEncodedRelayState = URLEncoder.encode(relayState, GeneralConstants.SAML_CHARSET_NAME);
byte[] sigValue = computeSignature(GeneralConstants.SAML_RESPONSE_KEY, urlEncodedResponse, urlEncodedRelayState, byte[] sigValue = computeSignature(GeneralConstants.SAML_RESPONSE_KEY, urlEncodedResponse, urlEncodedRelayState,
signingKey); signingKey);
@ -234,7 +234,7 @@ public class RedirectBindingSignatureUtil {
addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY,
RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY)); RedirectBindingSignatureUtil.getTokenValue(queryString, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY));
return SignatureUtil.validate(sb.toString().getBytes("UTF-8"), sigValue, validatingKey); return SignatureUtil.validate(sb.toString().getBytes(GeneralConstants.SAML_CHARSET), sigValue, validatingKey);
} }
private static boolean isRequestQueryString(String queryString) { private static boolean isRequestQueryString(String queryString) {
@ -257,7 +257,7 @@ public class RedirectBindingSignatureUtil {
String algo = signingKey.getAlgorithm(); String algo = signingKey.getAlgorithm();
String sigAlg = SignatureUtil.getXMLSignatureAlgorithmURI(algo); String sigAlg = SignatureUtil.getXMLSignatureAlgorithmURI(algo);
sigAlg = URLEncoder.encode(sigAlg, "UTF-8"); sigAlg = URLEncoder.encode(sigAlg, GeneralConstants.SAML_CHARSET_NAME);
addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, sigAlg); addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, sigAlg);
@ -291,7 +291,7 @@ public class RedirectBindingSignatureUtil {
// SigAlg // SigAlg
String sigAlg = SignatureUtil.getXMLSignatureAlgorithmURI(sigAlgo); String sigAlg = SignatureUtil.getXMLSignatureAlgorithmURI(sigAlgo);
sigAlg = URLEncoder.encode(sigAlg, "UTF-8"); sigAlg = URLEncoder.encode(sigAlg, GeneralConstants.SAML_CHARSET_NAME);
addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, sigAlg); addParameter(sb, GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, sigAlg);

View file

@ -16,6 +16,7 @@
*/ */
package org.keycloak.saml.processing.web.util; package org.keycloak.saml.processing.web.util;
import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.util.Base64; 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;
@ -43,7 +44,7 @@ public class RedirectBindingUtil {
* @throws IOException * @throws IOException
*/ */
public static String urlEncode(String str) throws IOException { public static String urlEncode(String str) throws IOException {
return URLEncoder.encode(str, "UTF-8"); return URLEncoder.encode(str, GeneralConstants.SAML_CHARSET_NAME);
} }
/** /**
@ -56,7 +57,7 @@ public class RedirectBindingUtil {
* @throws IOException * @throws IOException
*/ */
public static String urlDecode(String str) throws IOException { public static String urlDecode(String str) throws IOException {
return URLDecoder.decode(str, "UTF-8"); return URLDecoder.decode(str, GeneralConstants.SAML_CHARSET_NAME);
} }
/** /**
@ -97,7 +98,7 @@ public class RedirectBindingUtil {
* @throws IOException * @throws IOException
*/ */
public static String deflateBase64URLEncode(String stringToEncode) throws IOException { public static String deflateBase64URLEncode(String stringToEncode) throws IOException {
return deflateBase64URLEncode(stringToEncode.getBytes("UTF-8")); return deflateBase64URLEncode(stringToEncode.getBytes(GeneralConstants.SAML_CHARSET));
} }
/** /**

View file

@ -16,6 +16,8 @@
*/ */
package org.keycloak.saml.processing.core.parsers.saml; package org.keycloak.saml.processing.core.parsers.saml;
import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType; import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
import java.io.InputStream; import java.io.InputStream;
@ -27,8 +29,6 @@ import static org.hamcrest.CoreMatchers.*;
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType; import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
import org.keycloak.dom.saml.v2.protocol.ResponseType; import org.keycloak.dom.saml.v2.protocol.ResponseType;
import java.io.IOException;
import java.util.Scanner;
import org.junit.Before; import org.junit.Before;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@ -108,6 +108,38 @@ public class SAMLParserTest {
} }
} }
@Test
public void testSaml20AuthnResponseNonAsciiNameDefaultUtf8() throws Exception {
try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-3971-utf-8-no-header-authnresponse.xml")) {
Object parsedObject = parser.parse(st);
assertThat(parsedObject, instanceOf(ResponseType.class));
ResponseType rt = (ResponseType) parsedObject;
assertThat(rt.getAssertions().size(), is(1));
final AssertionType assertion = rt.getAssertions().get(0).getAssertion();
assertThat(assertion.getSubject().getSubType().getBaseID(), instanceOf(NameIDType.class));
NameIDType nameId = (NameIDType) assertion.getSubject().getSubType().getBaseID();
assertThat(nameId.getValue(), is("roàåאבčéèíñòøöùüßåäöü汉字"));
}
}
@Test
public void testSaml20AuthnResponseNonAsciiNameDefaultLatin2() throws Exception {
try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-3971-8859-2-in-header-authnresponse.xml")) {
Object parsedObject = parser.parse(st);
assertThat(parsedObject, instanceOf(ResponseType.class));
ResponseType rt = (ResponseType) parsedObject;
assertThat(rt.getAssertions().size(), is(1));
final AssertionType assertion = rt.getAssertions().get(0).getAssertion();
assertThat(assertion.getSubject().getSubType().getBaseID(), instanceOf(NameIDType.class));
NameIDType nameId = (NameIDType) assertion.getSubject().getSubType().getBaseID();
assertThat(nameId.getValue(), is("ročéíöüßäöü"));
}
}
@Test @Test
public void testSaml20PostLogoutRequest() throws Exception { public void testSaml20PostLogoutRequest() throws Exception {
try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-signed-logout-request.xml")) { try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-signed-logout-request.xml")) {

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="ISO-8859-2"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="http://localhost:8080/sales-post-sig/saml" ID="ID_670a76c7-8506-4081-80b3-5ef16df98af8" InResponseTo="ID_cc0ff6f7-b481-4c98-9a79-481d50958290" IssueInstant="2016-12-15T12:42:49.788Z" Version="2.0">
<saml:Issuer>http://localhost:11080/auth/realms/saml-demo</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_cf2e2b00-dfb0-4163-b8b5-f2d85586a235" IssueInstant="2016-12-15T12:42:49.787Z" Version="2.0">
<saml:Issuer>http://localhost:11080/auth/realms/saml-demo</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">roèéíöüßäöü</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData InResponseTo="ID_cc0ff6f7-b481-4c98-9a79-481d50958290" NotOnOrAfter="2016-12-15T12:47:47.787Z" Recipient="http://localhost:8080/sales-post-sig/saml"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2016-12-15T12:42:47.787Z" NotOnOrAfter="2016-12-15T12:43:47.787Z">
<saml:AudienceRestriction>
<saml:Audience>http://localhost:8080/sales-post-sig/</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2016-12-15T12:42:49.788Z" SessionIndex="fb5d5a23-aa34-4528-a29a-6aad8c0ef0e8">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">view-profile</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>

View file

@ -0,0 +1,30 @@
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="http://localhost:8080/sales-post-sig/saml" ID="ID_670a76c7-8506-4081-80b3-5ef16df98af8" InResponseTo="ID_cc0ff6f7-b481-4c98-9a79-481d50958290" IssueInstant="2016-12-15T12:42:49.788Z" Version="2.0">
<saml:Issuer>http://localhost:11080/auth/realms/saml-demo</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_cf2e2b00-dfb0-4163-b8b5-f2d85586a235" IssueInstant="2016-12-15T12:42:49.787Z" Version="2.0">
<saml:Issuer>http://localhost:11080/auth/realms/saml-demo</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">roàåאבčéèíñòøöùüßåäöü汉字</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData InResponseTo="ID_cc0ff6f7-b481-4c98-9a79-481d50958290" NotOnOrAfter="2016-12-15T12:47:47.787Z" Recipient="http://localhost:8080/sales-post-sig/saml"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2016-12-15T12:42:47.787Z" NotOnOrAfter="2016-12-15T12:43:47.787Z">
<saml:AudienceRestriction>
<saml:Audience>http://localhost:8080/sales-post-sig/</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2016-12-15T12:42:49.788Z" SessionIndex="fb5d5a23-aa34-4528-a29a-6aad8c0ef0e8">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">view-profile</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>