Skip to content

Commit 1f82f10

Browse files
committed
Merge branch 'master' of https://github.com/juazugas/java-saml into juazugas-master
2 parents 78523d8 + 2af62ba commit 1f82f10

17 files changed

Lines changed: 352 additions & 102 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ onelogin.saml2.contacts.support.email_address = support@example.com
361361

362362
##### KeyStores
363363

364-
The Auth constructor supports the ability to read SP public cert/private key from a KeyStore. A KeyStoreSettings object must be provided with the KeyStore, the Alias and the storePass if any.
364+
The Auth constructor supports the ability to read SP public cert/private key from a KeyStore. A KeyStoreSettings object must be provided with the KeyStore, the Alias and the KeyEntry password.
365365

366366
```java
367367
import java.io.FileInputStream;
@@ -370,13 +370,14 @@ import com.onelogin.saml2.Auth
370370
import com.onelogin.saml2.model.KeyStoreSettings
371371

372372
String keyStoreFile = "oneloginTestKeystore.jks";
373-
String alias = "onelogintest";
373+
String alias = "keywithpassword";
374374
String storePass = "changeit";
375+
String keyPassword = "keypassword";
375376

376377
KeyStore ks = KeyStore.getInstance("JKS");
377-
ks.load(new FileInputStream(keyStoreFile), password.toCharArray());
378+
ks.load(new FileInputStream(keyStoreFile), storePass.toCharArray());
378379

379-
KeyStoreSettings keyStoreSettings = new keyStoreSettings(ks, alias, storePass);
380+
KeyStoreSettings keyStoreSettings = new keyStoreSettings(ks, alias, keyPassword);
380381
Auth auth = new Auth(KeyStoreSettings keyStoreSetting);
381382
```
382383

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
import java.util.List;
99
import java.util.Map;
1010
import java.util.Objects;
11-
1211
import javax.xml.parsers.ParserConfigurationException;
1312
import javax.xml.xpath.XPathExpressionException;
14-
1513
import org.joda.time.DateTime;
1614
import org.joda.time.Instant;
1715
import org.slf4j.Logger;
@@ -22,7 +20,8 @@
2220
import org.w3c.dom.Node;
2321
import org.w3c.dom.NodeList;
2422
import org.xml.sax.SAXException;
25-
23+
import com.onelogin.saml2.exception.SettingsException;
24+
import com.onelogin.saml2.exception.ValidationError;
2625
import com.onelogin.saml2.http.HttpRequest;
2726
import com.onelogin.saml2.model.SamlResponseStatus;
2827
import com.onelogin.saml2.model.SubjectConfirmationIssue;
@@ -31,9 +30,6 @@
3130
import com.onelogin.saml2.util.SchemaFactory;
3231
import com.onelogin.saml2.util.Util;
3332

34-
import com.onelogin.saml2.exception.SettingsException;
35-
import com.onelogin.saml2.exception.ValidationError;
36-
3733
/**
3834
* SamlResponse class of OneLogin's Java Toolkit.
3935
*
@@ -553,18 +549,24 @@ public HashMap<String, List<String>> getAttributes() throws XPathExpressionExcep
553549
for (int i = 0; i < nodes.getLength(); i++) {
554550
NamedNodeMap attrName = nodes.item(i).getAttributes();
555551
String attName = attrName.getNamedItem("Name").getNodeValue();
556-
if (attributes.containsKey(attName)) {
552+
if (attributes.containsKey(attName) && !settings.isSpAllowRepeatAttributeName()) {
557553
throw new ValidationError("Found an Attribute element with duplicated Name", ValidationError.DUPLICATED_ATTRIBUTE_NAME_FOUND);
558554
}
559555

560556
NodeList childrens = nodes.item(i).getChildNodes();
561557

562-
List<String> attrValues = new ArrayList<String>();
558+
List<String> attrValues = null;
559+
if (attributes.containsKey(attName) && settings.isSpAllowRepeatAttributeName()) {
560+
attrValues = attributes.get(attName);
561+
} else {
562+
attrValues = new ArrayList<String>();
563+
}
563564
for (int j = 0; j < childrens.getLength(); j++) {
564565
if ("AttributeValue".equals(childrens.item(j).getLocalName())) {
565566
attrValues.add(childrens.item(j).getTextContent());
566567
}
567568
}
569+
568570
attributes.put(attName, attrValues);
569571
}
570572
LOGGER.debug("SAMLResponse has attributes: " + attributes.toString());

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,15 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
321321
if (nameIdFormat != null && nameIdFormat.equals(Constants.NAMEID_UNSPECIFIED)) {
322322
nameIdFormat = null;
323323
}
324-
324+
325325
X509Certificate cert = null;
326326
if (settings.getNameIdEncrypted()) {
327327
cert = settings.getIdpx509cert();
328+
if (cert == null) {
329+
List<X509Certificate> multipleCertList = settings.getIdpx509certMulti();
330+
if (multipleCertList != null && !multipleCertList.isEmpty())
331+
cert = multipleCertList.get(0);
332+
}
328333
}
329334

330335
String nameIdStr = Util.generateNameId(nameId, spNameQualifier, nameIdFormat, nameQualifier, cert);
@@ -429,19 +434,22 @@ public Boolean isValid() throws Exception {
429434

430435
if (signature != null && !signature.isEmpty()) {
431436
X509Certificate cert = settings.getIdpx509cert();
432-
if (cert == null) {
433-
throw new SettingsException("In order to validate the sign on the Logout Request, the x509cert of the IdP is required", SettingsException.CERT_NOT_FOUND);
434-
}
435-
437+
436438
List<X509Certificate> certList = new ArrayList<X509Certificate>();
437439
List<X509Certificate> multipleCertList = settings.getIdpx509certMulti();
438440

439441
if (multipleCertList != null && multipleCertList.size() != 0) {
440442
certList.addAll(multipleCertList);
441443
}
442444

443-
if (certList.isEmpty() || !certList.contains(cert)) {
444-
certList.add(0, cert);
445+
if (cert != null) {
446+
if (certList.isEmpty() || !certList.contains(cert)) {
447+
certList.add(0, cert);
448+
}
449+
}
450+
451+
if (certList.isEmpty()) {
452+
throw new SettingsException("In order to validate the sign on the Logout Request, the x509cert of the IdP is required", SettingsException.CERT_NOT_FOUND);
445453
}
446454

447455
String signAlg = request.getParameter("SigAlg");

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

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
* LogoutResponse class of OneLogin's Java Toolkit.
3333
*
3434
* A class that implements SAML 2 Logout Response builder/parser/validator
35-
*/
35+
*/
3636
public class LogoutResponse {
3737
/**
3838
* Private property to construct a logger for this class.
@@ -42,7 +42,7 @@ public class LogoutResponse {
4242
/**
4343
* SAML LogoutResponse string
4444
*/
45-
private String logoutResponseString;
45+
private String logoutResponseString;
4646

4747
/**
4848
* A DOMDocument object loaded from the SAML Response.
@@ -81,7 +81,7 @@ public class LogoutResponse {
8181

8282
/**
8383
* After validation, if it fails this property has the cause of the problem
84-
*/
84+
*/
8585
private String error;
8686

8787
/**
@@ -96,7 +96,7 @@ public class LogoutResponse {
9696
public LogoutResponse(Saml2Settings settings, HttpRequest request) {
9797
this.settings = settings;
9898
this.request = request;
99-
99+
100100
String samlLogoutResponse = null;
101101
if (request != null) {
102102
currentUrl = request.getRequestURL();
@@ -112,10 +112,10 @@ public LogoutResponse(Saml2Settings settings, HttpRequest request) {
112112
/**
113113
* @return the base64 encoded unsigned Logout Response (deflated or not)
114114
*
115-
* @param deflated
115+
* @param deflated
116116
* If deflated or not the encoded Logout Response
117117
*
118-
* @throws IOException
118+
* @throws IOException
119119
*/
120120
public String getEncodedLogoutResponse(Boolean deflated) throws IOException {
121121
String encodedLogoutResponse;
@@ -133,7 +133,7 @@ public String getEncodedLogoutResponse(Boolean deflated) throws IOException {
133133
/**
134134
* @return the base64 encoded, unsigned Logout Response (deflated or not)
135135
*
136-
* @throws IOException
136+
* @throws IOException
137137
*/
138138
public String getEncodedLogoutResponse() throws IOException {
139139
return getEncodedLogoutResponse(null);
@@ -230,9 +230,6 @@ public Boolean isValid(String requestId) {
230230

231231
if (signature != null && !signature.isEmpty()) {
232232
X509Certificate cert = settings.getIdpx509cert();
233-
if (cert == null) {
234-
throw new SettingsException("In order to validate the sign on the Logout Response, the x509cert of the IdP is required", SettingsException.CERT_NOT_FOUND);
235-
}
236233

237234
List<X509Certificate> certList = new ArrayList<X509Certificate>();
238235
List<X509Certificate> multipleCertList = settings.getIdpx509certMulti();
@@ -241,8 +238,14 @@ public Boolean isValid(String requestId) {
241238
certList.addAll(multipleCertList);
242239
}
243240

244-
if (certList.isEmpty() || !certList.contains(cert)) {
245-
certList.add(0, cert);
241+
if (cert != null) {
242+
if (certList.isEmpty() || !certList.contains(cert)) {
243+
certList.add(0, cert);
244+
}
245+
}
246+
247+
if (certList.isEmpty()) {
248+
throw new SettingsException("In order to validate the sign on the Logout Response, the x509cert of the IdP is required", SettingsException.CERT_NOT_FOUND);
246249
}
247250

248251
String signAlg = request.getParameter("SigAlg");
@@ -274,13 +277,13 @@ public Boolean isValid(String requestId) {
274277
}
275278
}
276279

277-
public Boolean isValid() {
280+
public Boolean isValid() {
278281
return isValid(null);
279282
}
280283

281284
/**
282285
* Gets the Issuer from Logout Response.
283-
*
286+
*
284287
* @return the issuer of the logout response
285288
*
286289
* @throws XPathExpressionException
@@ -290,7 +293,7 @@ public String getIssuer() throws XPathExpressionException {
290293
NodeList issuers = this.query("/samlp:LogoutResponse/saml:Issuer");
291294
if (issuers.getLength() == 1) {
292295
issuer = issuers.item(0).getTextContent();
293-
}
296+
}
294297
return issuer;
295298
}
296299

@@ -341,16 +344,28 @@ private NodeList query (String query) throws XPathExpressionException {
341344
*
342345
* @param inResponseTo
343346
* InResponseTo attribute value to bet set at the Logout Response.
347+
* @param statusCode
348+
* String StatusCode to be set on the LogoutResponse
344349
*/
345-
public void build(String inResponseTo) {
350+
public void build(String inResponseTo, String statusCode) {
346351
id = Util.generateUniqueID(settings.getUniqueIDPrefix());
347352
issueInstant = Calendar.getInstance();
348353
this.inResponseTo = inResponseTo;
349354

350-
StrSubstitutor substitutor = generateSubstitutor(settings);
355+
StrSubstitutor substitutor = generateSubstitutor(settings, statusCode);
351356
this.logoutResponseString = substitutor.replace(getLogoutResponseTemplate());
352357
}
353358

359+
/**
360+
* Generates a Logout Response XML string.
361+
*
362+
* @param inResponseTo
363+
* InResponseTo attribute value to bet set at the Logout Response.
364+
*/
365+
public void build(String inResponseTo) {
366+
build(inResponseTo, Constants.STATUS_SUCCESS);
367+
}
368+
354369
/**
355370
* Generates a Logout Response XML string.
356371
*
@@ -364,13 +379,15 @@ public void build() {
364379
*
365380
* @param settings
366381
* Saml2Settings object. Setting data
367-
*
368-
* @return the StrSubstitutor object of the LogoutResponse
382+
* @param statusCode
383+
* String StatusCode to be set on the LogoutResponse
384+
*
385+
* @return the StrSubstitutor object of the LogoutResponse
369386
*/
370-
private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
387+
private StrSubstitutor generateSubstitutor(Saml2Settings settings, String statusCode) {
371388
Map<String, String> valueMap = new HashMap<String, String>();
372389

373-
valueMap.put("id", id);
390+
valueMap.put("id", id);
374391

375392
String issueInstantString = Util.formatDateTime(issueInstant.getTimeInMillis());
376393
valueMap.put("issueInstant", issueInstantString);
@@ -388,11 +405,29 @@ private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
388405
}
389406
valueMap.put("inResponseStr", inResponseStr);
390407

408+
String statusStr = "";
409+
if (statusCode != null) {
410+
statusStr = "Value=\"" + statusCode + "\"";
411+
}
412+
valueMap.put("statusStr", statusStr);
413+
391414
valueMap.put("issuer", settings.getSpEntityId());
392415

393416
return new StrSubstitutor(valueMap);
394417
}
395418

419+
/**
420+
* Substitutes LogoutResponse variables within a string by values.
421+
*
422+
* @param settings
423+
* Saml2Settings object. Setting data
424+
*
425+
* @return the StrSubstitutor object of the LogoutResponse
426+
*/
427+
private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
428+
return generateSubstitutor(settings, Constants.STATUS_SUCCESS);
429+
}
430+
396431
/**
397432
* @return the LogoutResponse's template
398433
*/
@@ -404,7 +439,7 @@ private static StringBuilder getLogoutResponseTemplate() {
404439
template.append("IssueInstant=\"${issueInstant}\"${destinationStr}${inResponseStr} >");
405440
template.append("<saml:Issuer>${issuer}</saml:Issuer>");
406441
template.append("<samlp:Status>");
407-
template.append("<samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\" />");
442+
template.append("<samlp:StatusCode ${statusStr} />");
408443
template.append("</samlp:Status>");
409444
template.append("</samlp:LogoutResponse>");
410445
return template;
@@ -413,7 +448,7 @@ private static StringBuilder getLogoutResponseTemplate() {
413448
/**
414449
* After execute a validation process, if fails this method returns the cause
415450
*
416-
* @return the cause of the validation error
451+
* @return the cause of the validation error
417452
*/
418453
public String getError() {
419454
return error;

core/src/main/java/com/onelogin/saml2/model/KeyStoreSettings.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ public class KeyStoreSettings {
1919
private final String spAlias;
2020

2121
/**
22-
* Password for KeyStore
22+
* Password for KeyEntry in KeyStore
2323
*/
24-
private final String storePass;
24+
private final String spKeyPass;
2525

2626
/**
2727
* Constructor
@@ -32,13 +32,13 @@ public class KeyStoreSettings {
3232
* @param spAlias
3333
* Alias for SP key entry
3434
*
35-
* @param storePass
36-
* password to access KeyStore
35+
* @param spKeyPass
36+
* password to access Private KeyEntry in KeyStore
3737
*/
38-
public KeyStoreSettings(KeyStore keyStore, String spAlias, String storePass) {
38+
public KeyStoreSettings(KeyStore keyStore, String spAlias, String spKeyPass) {
3939
this.keyStore = keyStore;
4040
this.spAlias = spAlias;
41-
this.storePass = storePass;
41+
this.spKeyPass = spKeyPass;
4242
}
4343

4444
/**
@@ -56,10 +56,10 @@ public final String getSpAlias() {
5656
}
5757

5858
/**
59-
* @return the storePass
59+
* @return the spKeyPass
6060
*/
61-
public final String getStorePass() {
62-
return storePass;
61+
public final String getSpKeyPass() {
62+
return spKeyPass;
6363
}
6464

6565
}

0 commit comments

Comments
 (0)