Skip to content

Commit 38f3480

Browse files
authored
Merge pull request #315 from mauromol/escape-strings-in-xml
Properly escape text to produce valid XML
2 parents 8c66a14 + 3fd0098 commit 38f3480

File tree

12 files changed

+678
-47
lines changed

12 files changed

+678
-47
lines changed

core/src/main/java/com/onelogin/saml2/authn/AuthnRequest.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,15 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
206206
String destinationStr = "";
207207
URL sso = settings.getIdpSingleSignOnServiceUrl();
208208
if (sso != null) {
209-
destinationStr = " Destination=\"" + sso.toString() + "\"";
209+
destinationStr = " Destination=\"" + Util.toXml(sso.toString()) + "\"";
210210
}
211211
valueMap.put("destinationStr", destinationStr);
212212

213213
String subjectStr = "";
214214
if (nameIdValueReq != null && !nameIdValueReq.isEmpty()) {
215215
String nameIDFormat = settings.getSpNameIDFormat();
216216
subjectStr = "<saml:Subject>";
217-
subjectStr += "<saml:NameID Format=\"" + nameIDFormat + "\">" + nameIdValueReq + "</saml:NameID>";
217+
subjectStr += "<saml:NameID Format=\"" + Util.toXml(nameIDFormat) + "\">" + Util.toXml(nameIdValueReq) + "</saml:NameID>";
218218
subjectStr += "<saml:SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"></saml:SubjectConfirmation>";
219219
subjectStr += "</saml:Subject>";
220220
}
@@ -226,7 +226,7 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
226226
if (settings.getWantNameIdEncrypted()) {
227227
nameIDPolicyFormat = Constants.NAMEID_ENCRYPTED;
228228
}
229-
nameIDPolicyStr = "<samlp:NameIDPolicy Format=\"" + nameIDPolicyFormat + "\" AllowCreate=\"true\" />";
229+
nameIDPolicyStr = "<samlp:NameIDPolicy Format=\"" + Util.toXml(nameIDPolicyFormat) + "\" AllowCreate=\"true\" />";
230230
}
231231
valueMap.put("nameIDPolicyStr", nameIDPolicyStr);
232232

@@ -235,25 +235,25 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
235235
if (organization != null) {
236236
String displayName = organization.getOrgDisplayName();
237237
if (!displayName.isEmpty()) {
238-
providerStr = " ProviderName=\""+ displayName + "\"";
238+
providerStr = " ProviderName=\""+ Util.toXml(displayName) + "\"";
239239
}
240240
}
241241
valueMap.put("providerStr", providerStr);
242242

243243
String issueInstantString = Util.formatDateTime(issueInstant.getTimeInMillis());
244244
valueMap.put("issueInstant", issueInstantString);
245-
valueMap.put("id", String.valueOf(id));
246-
valueMap.put("assertionConsumerServiceURL", String.valueOf(settings.getSpAssertionConsumerServiceUrl()));
247-
valueMap.put("protocolBinding", settings.getSpAssertionConsumerServiceBinding());
248-
valueMap.put("spEntityid", settings.getSpEntityId());
245+
valueMap.put("id", Util.toXml(String.valueOf(id)));
246+
valueMap.put("assertionConsumerServiceURL", Util.toXml(String.valueOf(settings.getSpAssertionConsumerServiceUrl())));
247+
valueMap.put("protocolBinding", Util.toXml(settings.getSpAssertionConsumerServiceBinding()));
248+
valueMap.put("spEntityid", Util.toXml(settings.getSpEntityId()));
249249

250250
String requestedAuthnContextStr = "";
251251
List<String> requestedAuthnContexts = settings.getRequestedAuthnContext();
252252
if (requestedAuthnContexts != null && !requestedAuthnContexts.isEmpty()) {
253253
String requestedAuthnContextCmp = settings.getRequestedAuthnContextComparison();
254-
requestedAuthnContextStr = "<samlp:RequestedAuthnContext Comparison=\"" + requestedAuthnContextCmp + "\">";
254+
requestedAuthnContextStr = "<samlp:RequestedAuthnContext Comparison=\"" + Util.toXml(requestedAuthnContextCmp) + "\">";
255255
for (String requestedAuthnContext : requestedAuthnContexts) {
256-
requestedAuthnContextStr += "<saml:AuthnContextClassRef>" + requestedAuthnContext + "</saml:AuthnContextClassRef>";
256+
requestedAuthnContextStr += "<saml:AuthnContextClassRef>" + Util.toXml(requestedAuthnContext) + "</saml:AuthnContextClassRef>";
257257
}
258258
requestedAuthnContextStr += "</samlp:RequestedAuthnContext>";
259259
}

core/src/main/java/com/onelogin/saml2/logout/LogoutRequest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,19 +294,19 @@ public String getLogoutRequestXml() {
294294
private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
295295
Map<String, String> valueMap = new HashMap<String, String>();
296296

297-
valueMap.put("id", id);
297+
valueMap.put("id", Util.toXml(id));
298298

299299
String issueInstantString = Util.formatDateTime(issueInstant.getTimeInMillis());
300300
valueMap.put("issueInstant", issueInstantString);
301301

302302
String destinationStr = "";
303303
URL slo = settings.getIdpSingleLogoutServiceUrl();
304304
if (slo != null) {
305-
destinationStr = " Destination=\"" + slo.toString() + "\"";
305+
destinationStr = " Destination=\"" + Util.toXml(slo.toString()) + "\"";
306306
}
307307
valueMap.put("destinationStr", destinationStr);
308308

309-
valueMap.put("issuer", settings.getSpEntityId());
309+
valueMap.put("issuer", Util.toXml(settings.getSpEntityId()));
310310

311311
String nameIdFormat = null;
312312
String spNameQualifier = this.nameIdSPNameQualifier;
@@ -349,7 +349,7 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
349349

350350
String sessionIndexStr = "";
351351
if (sessionIndex != null) {
352-
sessionIndexStr = " <samlp:SessionIndex>" + sessionIndex + "</samlp:SessionIndex>";
352+
sessionIndexStr = " <samlp:SessionIndex>" + Util.toXml(sessionIndex) + "</samlp:SessionIndex>";
353353
}
354354
valueMap.put("sessionIndexStr", sessionIndexStr);
355355

core/src/main/java/com/onelogin/saml2/logout/LogoutResponse.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,31 +421,31 @@ protected String postProcessXml(final String logoutResponseXml, final Saml2Setti
421421
private StrSubstitutor generateSubstitutor(Saml2Settings settings, String statusCode) {
422422
Map<String, String> valueMap = new HashMap<String, String>();
423423

424-
valueMap.put("id", id);
424+
valueMap.put("id", Util.toXml(id));
425425

426426
String issueInstantString = Util.formatDateTime(issueInstant.getTimeInMillis());
427427
valueMap.put("issueInstant", issueInstantString);
428428

429429
String destinationStr = "";
430430
URL slo = settings.getIdpSingleLogoutServiceResponseUrl();
431431
if (slo != null) {
432-
destinationStr = " Destination=\"" + slo.toString() + "\"";
432+
destinationStr = " Destination=\"" + Util.toXml(slo.toString()) + "\"";
433433
}
434434
valueMap.put("destinationStr", destinationStr);
435435

436436
String inResponseStr = "";
437437
if (inResponseTo != null) {
438-
inResponseStr = " InResponseTo=\"" + inResponseTo + "\"";
438+
inResponseStr = " InResponseTo=\"" + Util.toXml(inResponseTo) + "\"";
439439
}
440440
valueMap.put("inResponseStr", inResponseStr);
441441

442442
String statusStr = "";
443443
if (statusCode != null) {
444-
statusStr = "Value=\"" + statusCode + "\"";
444+
statusStr = "Value=\"" + Util.toXml(statusCode) + "\"";
445445
}
446446
valueMap.put("statusStr", statusStr);
447447

448-
valueMap.put("issuer", settings.getSpEntityId());
448+
valueMap.put("issuer", Util.toXml(settings.getSpEntityId()));
449449

450450
return new StrSubstitutor(valueMap);
451451
}

core/src/main/java/com/onelogin/saml2/settings/Metadata.java

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.onelogin.saml2.settings;
22

3+
import static com.onelogin.saml2.util.Util.toXml;
4+
35
import java.net.URL;
46
import java.util.Arrays;
57
import java.util.Calendar;
@@ -146,7 +148,7 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) throws Certif
146148
Map<String, String> valueMap = new HashMap<String, String>();
147149
Boolean wantsEncrypted = settings.getWantAssertionsEncrypted() || settings.getWantNameIdEncrypted();
148150

149-
valueMap.put("id", Util.generateUniqueID(settings.getUniqueIDPrefix()));
151+
valueMap.put("id", Util.toXml(Util.generateUniqueID(settings.getUniqueIDPrefix())));
150152
String validUntilTimeStr = "";
151153
if (validUntilTime != null) {
152154
String validUntilTimeValue = Util.formatDateTime(validUntilTime.getTimeInMillis());
@@ -161,12 +163,12 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) throws Certif
161163
}
162164
valueMap.put("cacheDurationStr", cacheDurationStr);
163165

164-
valueMap.put("spEntityId", settings.getSpEntityId());
166+
valueMap.put("spEntityId", Util.toXml(settings.getSpEntityId()));
165167
valueMap.put("strAuthnsign", String.valueOf(settings.getAuthnRequestsSigned()));
166168
valueMap.put("strWsign", String.valueOf(settings.getWantAssertionsSigned()));
167-
valueMap.put("spNameIDFormat", settings.getSpNameIDFormat());
168-
valueMap.put("spAssertionConsumerServiceBinding", settings.getSpAssertionConsumerServiceBinding());
169-
valueMap.put("spAssertionConsumerServiceUrl", settings.getSpAssertionConsumerServiceUrl().toString());
169+
valueMap.put("spNameIDFormat", Util.toXml(settings.getSpNameIDFormat()));
170+
valueMap.put("spAssertionConsumerServiceBinding", Util.toXml(settings.getSpAssertionConsumerServiceBinding()));
171+
valueMap.put("spAssertionConsumerServiceUrl", Util.toXml(settings.getSpAssertionConsumerServiceUrl().toString()));
170172
valueMap.put("sls", toSLSXml(settings.getSpSingleLogoutServiceUrl(), settings.getSpSingleLogoutServiceBinding()));
171173

172174
valueMap.put("strAttributeConsumingService", getAttributeConsumingServiceXml());
@@ -218,10 +220,10 @@ private String getAttributeConsumingServiceXml() {
218220

219221
attributeConsumingServiceXML.append("<md:AttributeConsumingService index=\"1\">");
220222
if (serviceName != null && !serviceName.isEmpty()) {
221-
attributeConsumingServiceXML.append("<md:ServiceName xml:lang=\"en\">" + serviceName + "</md:ServiceName>");
223+
attributeConsumingServiceXML.append("<md:ServiceName xml:lang=\"en\">" + Util.toXml(serviceName) + "</md:ServiceName>");
222224
}
223225
if (serviceDescription != null && !serviceDescription.isEmpty()) {
224-
attributeConsumingServiceXML.append("<md:ServiceDescription xml:lang=\"en\">" + serviceDescription + "</md:ServiceDescription>");
226+
attributeConsumingServiceXML.append("<md:ServiceDescription xml:lang=\"en\">" + Util.toXml(serviceDescription) + "</md:ServiceDescription>");
225227
}
226228
if (requestedAttributes != null && !requestedAttributes.isEmpty()) {
227229
for (RequestedAttribute requestedAttribute : requestedAttributes) {
@@ -234,15 +236,15 @@ private String getAttributeConsumingServiceXml() {
234236
String contentStr = "<md:RequestedAttribute";
235237

236238
if (name != null && !name.isEmpty()) {
237-
contentStr += " Name=\"" + name + "\"";
239+
contentStr += " Name=\"" + Util.toXml(name) + "\"";
238240
}
239241

240242
if (nameFormat != null && !nameFormat.isEmpty()) {
241-
contentStr += " NameFormat=\"" + nameFormat + "\"";
243+
contentStr += " NameFormat=\"" + Util.toXml(nameFormat) + "\"";
242244
}
243245

244246
if (friendlyName != null && !friendlyName.isEmpty()) {
245-
contentStr += " FriendlyName=\"" + friendlyName + "\"";
247+
contentStr += " FriendlyName=\"" + Util.toXml(friendlyName) + "\"";
246248
}
247249

248250
if (isRequired != null) {
@@ -252,7 +254,7 @@ private String getAttributeConsumingServiceXml() {
252254
if (attrValues != null && !attrValues.isEmpty()) {
253255
contentStr += ">";
254256
for (String attrValue : attrValues) {
255-
contentStr += "<saml:AttributeValue xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + attrValue + "</saml:AttributeValue>";
257+
contentStr += "<saml:AttributeValue xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + Util.toXml(attrValue) + "</saml:AttributeValue>";
256258
}
257259
attributeConsumingServiceXML.append(contentStr + "</md:RequestedAttribute>");
258260
} else {
@@ -276,9 +278,9 @@ private String toContactsXml(List<Contact> contacts) {
276278
StringBuilder contactsXml = new StringBuilder();
277279

278280
for (Contact contact : contacts) {
279-
contactsXml.append("<md:ContactPerson contactType=\"" + contact.getContactType() + "\">");
280-
contactsXml.append("<md:GivenName>" + contact.getGivenName() + "</md:GivenName>");
281-
contactsXml.append("<md:EmailAddress>" + contact.getEmailAddress() + "</md:EmailAddress>");
281+
contactsXml.append("<md:ContactPerson contactType=\"" + Util.toXml(contact.getContactType()) + "\">");
282+
contactsXml.append("<md:GivenName>" + Util.toXml(contact.getGivenName()) + "</md:GivenName>");
283+
contactsXml.append("<md:EmailAddress>" + Util.toXml(contact.getEmailAddress()) + "</md:EmailAddress>");
282284
contactsXml.append("</md:ContactPerson>");
283285
}
284286

@@ -296,10 +298,10 @@ private String toOrganizationXml(Organization organization) {
296298

297299
if (organization != null) {
298300
String lang = organization.getOrgLangAttribute();
299-
orgXml = "<md:Organization><md:OrganizationName xml:lang=\"" + lang + "\">" + organization.getOrgName()
300-
+ "</md:OrganizationName><md:OrganizationDisplayName xml:lang=\"" + lang + "\">"
301-
+ organization.getOrgDisplayName() + "</md:OrganizationDisplayName><md:OrganizationURL xml:lang=\""
302-
+ lang + "\">" + organization.getOrgUrl() + "</md:OrganizationURL></md:Organization>";
301+
orgXml = "<md:Organization><md:OrganizationName xml:lang=\"" + Util.toXml(lang) + "\">" + Util.toXml(organization.getOrgName())
302+
+ "</md:OrganizationName><md:OrganizationDisplayName xml:lang=\"" + Util.toXml(lang) + "\">"
303+
+ Util.toXml(organization.getOrgDisplayName()) + "</md:OrganizationDisplayName><md:OrganizationURL xml:lang=\""
304+
+ Util.toXml(lang) + "\">" + Util.toXml(organization.getOrgUrl()) + "</md:OrganizationURL></md:Organization>";
303305
}
304306
return orgXml;
305307
}
@@ -363,8 +365,8 @@ private String toSLSXml(URL spSingleLogoutServiceUrl, String spSingleLogoutServi
363365
StringBuilder slsXml = new StringBuilder();
364366

365367
if (spSingleLogoutServiceUrl != null) {
366-
slsXml.append("<md:SingleLogoutService Binding=\"" + spSingleLogoutServiceBinding + "\"");
367-
slsXml.append(" Location=\"" + spSingleLogoutServiceUrl.toString() + "\"/>");
368+
slsXml.append("<md:SingleLogoutService Binding=\"" + Util.toXml(spSingleLogoutServiceBinding) + "\"");
369+
slsXml.append(" Location=\"" + Util.toXml(spSingleLogoutServiceUrl.toString()) + "\"/>");
368370
}
369371
return slsXml.toString();
370372
}

core/src/main/java/com/onelogin/saml2/util/Util.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@
6363
import javax.xml.xpath.XPathFactory;
6464
import javax.xml.xpath.XPathFactoryConfigurationException;
6565

66-
import com.onelogin.saml2.model.hsm.HSM;
6766
import org.apache.commons.codec.binary.Base64;
6867
import org.apache.commons.codec.digest.DigestUtils;
68+
import org.apache.commons.lang3.StringEscapeUtils;
6969
import org.apache.commons.lang3.StringUtils;
7070
import org.apache.xml.security.encryption.EncryptedData;
7171
import org.apache.xml.security.encryption.EncryptedKey;
@@ -95,6 +95,7 @@
9595
import com.onelogin.saml2.exception.ValidationError;
9696
import com.onelogin.saml2.exception.XMLEntityException;
9797
import com.onelogin.saml2.model.SamlResponseStatus;
98+
import com.onelogin.saml2.model.hsm.HSM;
9899

99100

100101
/**
@@ -445,7 +446,7 @@ public static String convertDocumentToString(Document doc, Boolean c14n) {
445446
* @return the Document object
446447
*/
447448
public static String convertDocumentToString(Document doc) {
448-
return convertDocumentToString(doc, false);
449+
return convertDocumentToString(doc, false);
449450
}
450451

451452
/**
@@ -1976,6 +1977,17 @@ public static DateTime parseDateTime(String dateTime) {
19761977
}
19771978
return parsedData;
19781979
}
1980+
1981+
/**
1982+
* Escape a text so that it can be safely used within an XML element contents or attribute value.
1983+
*
1984+
* @param text
1985+
* the text to escape
1986+
* @return the escaped text (<code>null</code> if the input is <code>null</code>)
1987+
*/
1988+
public static String toXml(String text) {
1989+
return StringEscapeUtils.escapeXml10(text);
1990+
}
19791991

19801992
private static String toStringUtf8(byte[] bytes) {
19811993
try {

0 commit comments

Comments
 (0)