You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2018/07/13 17:03:10 UTC
[cxf-fediz] 04/04: FEDIZ-221 - Return errors in a LogoutResponse as
well
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf-fediz.git
commit 43b07bed4dc0434dac7d66be4fe8c9c21f83fcf8
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Fri Jul 13 17:48:03 2018 +0100
FEDIZ-221 - Return errors in a LogoutResponse as well
---
.../idp/beans/samlsso/AuthnRequestParser.java | 2 +-
.../beans/samlsso/SamlResponseErrorCreator.java | 48 ++++++++++++++++++----
.../webapp/WEB-INF/flows/saml-validate-request.xml | 23 +++++++++--
.../apache/cxf/fediz/systests/samlsso/IdpTest.java | 32 ++++++++++++---
4 files changed, 86 insertions(+), 19 deletions(-)
diff --git a/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestParser.java b/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestParser.java
index 6b6b88a..f501458 100644
--- a/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestParser.java
+++ b/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/AuthnRequestParser.java
@@ -122,11 +122,11 @@ public class AuthnRequestParser {
WebUtils.putAttributeInFlowScope(context, IdpConstants.SAML_AUTHN_REQUEST, authnRequest);
} else if (parsedRequest instanceof LogoutRequest) {
SAMLLogoutRequest logoutRequest = new SAMLLogoutRequest((LogoutRequest)parsedRequest);
+ WebUtils.putAttributeInFlowScope(context, IdpConstants.SAML_LOGOUT_REQUEST, logoutRequest);
if (logoutRequest.getNotOnOrAfter() != null && (new Date()).after(logoutRequest.getNotOnOrAfter())) {
LOG.debug("The LogoutRequest is expired");
throw new ProcessingException(TYPE.BAD_REQUEST);
}
- WebUtils.putAttributeInFlowScope(context, IdpConstants.SAML_LOGOUT_REQUEST, logoutRequest);
}
validateRequest(parsedRequest);
diff --git a/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseErrorCreator.java b/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseErrorCreator.java
index 761883a..d201d0a 100644
--- a/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseErrorCreator.java
+++ b/services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/beans/samlsso/SamlResponseErrorCreator.java
@@ -33,6 +33,7 @@ import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder;
import org.apache.wss4j.common.saml.OpenSAMLUtil;
import org.apache.wss4j.common.util.DOM2Writer;
+import org.opensaml.saml.saml2.core.LogoutResponse;
import org.opensaml.saml.saml2.core.Response;
import org.opensaml.saml.saml2.core.Status;
import org.slf4j.Logger;
@@ -48,25 +49,32 @@ public class SamlResponseErrorCreator {
private static final Logger LOG = LoggerFactory.getLogger(SamlResponseErrorCreator.class);
private boolean supportDeflateEncoding;
+ private boolean useRealmForIssuer;
- public String createSAMLResponse(RequestContext context, boolean requestor,
- Idp idp, String requestID) throws ProcessingException {
+ public String createSAMLResponse(RequestContext context, boolean logout, boolean requestor,
+ Idp idp, String requestID, String destination) throws ProcessingException {
Document doc = DOMUtils.newDocument();
String statusValue = "urn:oasis:names:tc:SAML:2.0:status:Responder";
if (requestor) {
statusValue = "urn:oasis:names:tc:SAML:2.0:status:Requester";
}
+
Status status =
SAML2PResponseComponentBuilder.createStatus(statusValue, null);
- Response response =
- SAML2PResponseComponentBuilder.createSAMLResponse(requestID, idp.getRealm(), status);
-
+ Element responseElement = null;
try {
- Element policyElement = OpenSAMLUtil.toDom(response, doc);
- doc.appendChild(policyElement);
+ if (logout) {
+ responseElement = createLogoutResponse(idp, statusValue, destination, requestID);
+ } else {
+ Response response =
+ SAML2PResponseComponentBuilder.createSAMLResponse(requestID, idp.getRealm(), status);
+ Element policyElement = OpenSAMLUtil.toDom(response, doc);
+ doc.appendChild(policyElement);
+
+ responseElement = policyElement;
+ }
- Element responseElement = policyElement;
return encodeResponse(responseElement);
} catch (Exception e) {
LOG.warn("Error marshalling SAML Token: {}", e.getMessage());
@@ -74,6 +82,22 @@ public class SamlResponseErrorCreator {
}
}
+ protected Element createLogoutResponse(Idp idp, String statusValue,
+ String destination, String requestID) throws Exception {
+ Document doc = DOMUtils.newDocument();
+
+ Status status =
+ SAML2PResponseComponentBuilder.createStatus(statusValue, null);
+ String issuer = useRealmForIssuer ? idp.getRealm() : idp.getIdpUrl().toString();
+ LogoutResponse response =
+ SAML2PResponseComponentBuilder.createSAMLLogoutResponse(requestID, issuer, status, destination);
+
+ Element policyElement = OpenSAMLUtil.toDom(response, doc);
+ doc.appendChild(policyElement);
+
+ return policyElement;
+ }
+
protected String encodeResponse(Element response) throws IOException {
String responseMessage = DOM2Writer.nodeToString(response);
LOG.debug("Created Response: {}", responseMessage);
@@ -95,4 +119,12 @@ public class SamlResponseErrorCreator {
public void setSupportDeflateEncoding(boolean supportDeflateEncoding) {
this.supportDeflateEncoding = supportDeflateEncoding;
}
+
+ public boolean isUseRealmForIssuer() {
+ return useRealmForIssuer;
+ }
+
+ public void setUseRealmForIssuer(boolean useRealmForIssuer) {
+ this.useRealmForIssuer = useRealmForIssuer;
+ }
}
diff --git a/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml b/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
index 61cdadc..ce6c253 100644
--- a/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
+++ b/services/idp/src/main/webapp/WEB-INF/flows/saml-validate-request.xml
@@ -272,8 +272,10 @@
result="requestScope.samlAction"/>
</on-entry>
<!-- See if we managed to at least parse the request to get the response URL -->
- <if test="requestScope.samlAction == null or requestScope.samlAction.isEmpty()"
- then="viewBadRequestParsingError" else="viewBadRequestResponse"/>
+ <if test="requestScope.samlAction == null or requestScope.samlAction.isEmpty() or requestScope.samlAction == '/'"
+ then="viewBadRequestParsingError"/>
+ <if test="flowScope.saml_logout_request != null"
+ then="viewBadLogoutRequestResponse" else="viewBadRequestResponse"/>
</decision-state>
<end-state id="viewBadRequestResponse" view="samlsigninresponseform">
@@ -283,8 +285,21 @@
<evaluate expression="authnRequestParser.retrieveRequestId(flowRequestContext)"
result="flowScope.requestId"/>
<evaluate expression="flowScope.RelayState" result="requestScope.relayState" />
- <evaluate expression="samlResponseErrorCreator.createSAMLResponse(flowRequestContext, true, flowScope.idpConfig,
- flowScope.requestId)"
+ <evaluate expression="samlResponseErrorCreator.createSAMLResponse(flowRequestContext, false,
+ true, flowScope.idpConfig, flowScope.requestId, requestScope.samlAction)"
+ result="requestScope.samlResponse"/>
+ </on-entry>
+ </end-state>
+
+ <end-state id="viewBadLogoutRequestResponse" view="samlsignoutresponseform">
+ <on-entry>
+ <evaluate expression="authnRequestParser.retrieveConsumerURL(flowRequestContext)"
+ result="requestScope.samlAction"/>
+ <evaluate expression="authnRequestParser.retrieveRequestId(flowRequestContext)"
+ result="flowScope.requestId"/>
+ <evaluate expression="flowScope.RelayState" result="requestScope.relayState" />
+ <evaluate expression="samlResponseErrorCreator.createSAMLResponse(flowRequestContext, true,
+ true, flowScope.idpConfig, flowScope.requestId, requestScope.samlAction)"
result="requestScope.samlResponse"/>
</on-entry>
</end-state>
diff --git a/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/samlsso/IdpTest.java b/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/samlsso/IdpTest.java
index ee76fd4..d83b06a 100644
--- a/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/samlsso/IdpTest.java
+++ b/systests/samlsso/src/test/java/org/apache/cxf/fediz/systests/samlsso/IdpTest.java
@@ -1732,6 +1732,10 @@ public class IdpTest {
LogoutResponse logoutResponse = (LogoutResponse)OpenSAMLUtil.fromDom(responseDoc.getDocumentElement());
Assert.assertNotNull(logoutResponse);
Assert.assertEquals("https://localhost:8080/logout", logoutResponse.getDestination());
+ String expectedIssuer = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml";
+ Assert.assertEquals(expectedIssuer, logoutResponse.getIssuer().getValue());
+ String success = "urn:oasis:names:tc:SAML:2.0:status:Success";
+ Assert.assertEquals(success, logoutResponse.getStatus().getStatusCode().getValue());
webClient.close();
@@ -1838,12 +1842,28 @@ public class IdpTest {
new UsernamePasswordCredentials(user, password));
webClient.getOptions().setJavaScriptEnabled(false);
- try {
- webClient.getPage(logoutURL);
- Assert.fail("Authentication failure expected");
- } catch (FailingHttpStatusCodeException ex) {
- Assert.assertEquals(ex.getStatusCode(), 400);
- }
+ idpPage = webClient.getPage(logoutURL);
+ webClient.getOptions().setJavaScriptEnabled(true);
+
+ // Check Response
+ HtmlForm responseForm = idpPage.getFormByName("samlsignoutresponseform");
+ Assert.assertEquals("https://localhost:8080/logout", responseForm.getActionAttribute());
+ String responseValue = responseForm.getInputByName("SAMLResponse").getAttributeNS(null, "value");
+ Assert.assertNotNull(responseValue);
+ String receivedRelayState = responseForm.getInputByName("RelayState").getAttributeNS(null, "value");
+ Assert.assertEquals(relayState, receivedRelayState);
+
+ byte[] deflatedToken = Base64Utility.decode(responseValue);
+ InputStream tokenStream = new ByteArrayInputStream(deflatedToken);
+ Document responseDoc = StaxUtils.read(new InputStreamReader(tokenStream, StandardCharsets.UTF_8));
+
+ LogoutResponse logoutResponse = (LogoutResponse)OpenSAMLUtil.fromDom(responseDoc.getDocumentElement());
+ Assert.assertNotNull(logoutResponse);
+ Assert.assertEquals("https://localhost:8080/logout", logoutResponse.getDestination());
+ String expectedIssuer = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/saml";
+ Assert.assertEquals(expectedIssuer, logoutResponse.getIssuer().getValue());
+ String success = "urn:oasis:names:tc:SAML:2.0:status:Requester";
+ Assert.assertEquals(success, logoutResponse.getStatus().getStatusCode().getValue());
webClient.close();
// 3. now we try to access the idp without authentication but with the existing cookies