diff --git a/README.md b/README.md
index ada106f..afa5697 100644
--- a/README.md
+++ b/README.md
@@ -658,6 +658,9 @@ The following is an example of metadata for the example configuration:
+
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
diff --git a/auth_mellon_handler.c b/auth_mellon_handler.c
index 3e0bf57..50573ff 100644
--- a/auth_mellon_handler.c
+++ b/auth_mellon_handler.c
@@ -190,6 +190,9 @@ static char *am_generate_metadata(apr_pool_t *p, request_rec *r)
\n\
+ \n\
urn:oasis:names:tc:SAML:2.0:nameid-format:transient\n\
msg_url);
+ message = am_htmlencode(r, profile->msg_body);
+ if (profile->msg_relayState != NULL) {
+ relay_state = am_htmlencode(r, profile->msg_relayState);
+ } else {
+ /* Try to get relayState from post_data (lasso seems not to initialize relayState from post logout) */
+ int rc = 0;
+ relay_state = am_extract_query_parameter(r->pool, post_data,
+ "RelayState");
+ if (relay_state) {
+ rc = am_urldecode(relay_state);
+ if (rc != OK) {
+ AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, rc, r,
+ "Could not urldecode RelayState value.");
+ relay_state = NULL;
+ }
+ }
+ }
+
+ if (relay_state) {
+ output = apr_psprintf(r->pool,
+ "\n"
+ "\n"
+ " \n"
+ " \n"
+ " POST data\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "\n",
+ url, message, relay_state);
+ } else {
+ output = apr_psprintf(r->pool,
+ "\n"
+ "\n"
+ " \n"
+ " \n"
+ " POST data\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "\n",
+ url, message);
+ }
+
+ ap_set_content_type(r, "text/html");
+ ap_rputs(output, r);
+
+ return OK;
+}
/* Returns a SAML response
*
* Parameters:
* request_rec *r The current request.
* LassoProfile *profile The profile object.
+ * char *post_data The post data (if present for POST logout)
*
* Returns:
* HTTP_INTERNAL_SERVER_ERROR if an error occurs, HTTP_SEE_OTHER for the
* Redirect binding and OK for the SOAP binding.
*/
static int am_return_logout_response(request_rec *r,
- LassoProfile *profile)
+ LassoProfile *profile,
+ char *post_data)
{
if (profile->msg_url && profile->msg_body) {
/* POST binding response */
- AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
- "Error building logout response message."
- " POST binding is unsupported.");
- return HTTP_INTERNAL_SERVER_ERROR;
+ return am_set_logout_response_post_content(r, profile, post_data);
} else if (profile->msg_url) {
/* HTTP-Redirect binding response */
apr_table_setn(r->headers_out, "Location",
@@ -655,12 +745,16 @@ static void am_restore_lasso_profile_state(request_rec *r,
* request_rec *r The logout request.
* LassoLogout *logout A LassoLogout object initiated with
* the current session.
+ * char *msg The logout message to process.
+ * char *post_data The post data (if present for POST logout)
*
* Returns:
* OK on success, or an error if any of the steps fail.
*/
static int am_handle_logout_request(request_rec *r,
- LassoLogout *logout, char *msg)
+ LassoLogout *logout,
+ char *msg,
+ char *post_data)
{
gint res = 0, rc = HTTP_OK;
am_cache_entry_t *session = NULL;
@@ -753,7 +847,7 @@ static int am_handle_logout_request(request_rec *r,
rc = HTTP_INTERNAL_SERVER_ERROR;
goto exit;
}
- rc = am_return_logout_response(r, &logout->parent);
+ rc = am_return_logout_response(r, &logout->parent, post_data);
exit:
if (session != NULL) {
@@ -764,6 +858,43 @@ static int am_handle_logout_request(request_rec *r,
return rc;
}
+/* This function handles an IdP initiated logout request HTTP-POST.
+ *
+ * Parameters:
+ * request_rec *r The logout request.
+ * LassoLogout *logout A LassoLogout object initiated with
+ * the current session.
+ * char *post_data The post data (if present for POST logout)
+ *
+ * Returns:
+ * OK on success, or an error if any of the steps fail.
+ */
+static int am_handle_logout_request_POST(request_rec *r,
+ LassoLogout *logout,
+ char *post_data)
+{
+ int rc = 0;
+ char *saml_request;
+
+ saml_request = am_extract_query_parameter(r->pool, post_data,
+ "SAMLRequest");
+
+ if (saml_request == NULL) {
+ AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, rc, r,
+ "Could not find SAMLRequest field in POST data.");
+ return HTTP_BAD_REQUEST;
+ }
+
+ rc = am_urldecode(saml_request);
+ if (rc != OK) {
+ AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, rc, r,
+ "Could not urldecode SAMLRequest value.");
+ return rc;
+ }
+
+ return am_handle_logout_request(r, logout, saml_request, post_data);
+}
+
/* This function handles an invalidate request.
*
* Parameters:
@@ -1169,7 +1300,7 @@ static int am_handle_logout(request_rec *r)
/*
* First check for POST method, which could be either IdP-initiated SOAP
- * logout request or POST logout response from IdP.
+ * or HTTP-POST logout request or POST logout response from IdP.
*/
if ((r->args == NULL) && (r->method_number == M_POST)) {
int rc;
@@ -1187,14 +1318,22 @@ static int am_handle_logout(request_rec *r)
}
if (content_type != NULL &&
- am_has_header(r, content_type, "application/x-www-form-urlencoded"))
+ am_has_header(r, content_type, "application/x-www-form-urlencoded")) {
+ /* POST can be for a SAMLRequest (IDP request for SLO) or a SAMLResponse (IDP response for SLO) */
+ char *saml_param;
+ saml_param = am_extract_query_parameter(r->pool, post_data,
+ "SAMLResponse");
+ if (saml_param) {
return am_handle_logout_response_POST(r, logout, post_data);
- else
- return am_handle_logout_request(r, logout, post_data);
+ }
+ }
+
+ /* HTTP-POST Request */
+ return am_handle_logout_request_POST(r, logout, post_data);
} else if(am_extract_query_parameter(r->pool, r->args,
"SAMLRequest") != NULL) {
/* SAMLRequest - logout request from the IdP. */
- return am_handle_logout_request(r, logout, r->args);
+ return am_handle_logout_request(r, logout, r->args, r->args);
} else if(am_extract_query_parameter(r->pool, r->args,
"SAMLResponse") != NULL) {
diff --git a/auth_mellon_util.c b/auth_mellon_util.c
index 6a686db..0dcf124 100644
--- a/auth_mellon_util.c
+++ b/auth_mellon_util.c
@@ -2451,6 +2451,7 @@ int am_get_boolean_query_parameter(request_rec *r, const char *name,
* "AuthnRequestsSigned"
* "AssertionConsumerService PAOS 2"
* "SingleLogoutService HTTP-Redirect"
+ * "SingleLogoutService HTTP-POST"
* "SingleLogoutService SOAP"
* "AssertionConsumerService HTTP-Artifact 1"
* "NameIDFormat"
diff --git a/doc/user_guide/mellon_user_guide.adoc b/doc/user_guide/mellon_user_guide.adoc
index ff050e6..296c21e 100644
--- a/doc/user_guide/mellon_user_guide.adoc
+++ b/doc/user_guide/mellon_user_guide.adoc
@@ -1105,17 +1105,20 @@ our example authentication.
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://mellon.example.com/mellon/logout" />
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
-
+
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+ Location="https://mellon.example.com/mellon/logout" />
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
index="0"
- isDefault="true"
+ isDefault="true"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://mellon.example.com/mellon/postResponse" />
-
+
index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="https://mellon.example.com/mellon/artifactResponse" />
-
+
index="2"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
Location="https://mellon.example.com/mellon/paosResponse" />
@@ -1173,21 +1176,24 @@ this URL location.
<10> SAML endpoint. Logout messages using the HTTP-Redirect binding
are sent to this URL location.
-<11> Zero or more `` elements enumerate the name
+<11> SAML endpoint. Logout messages using the HTTP-POST binding
+are sent to this URL location.
+
+<12> Zero or more `` elements enumerate the name
identifier formats supported by this entity. See <> for
details.
-<12> [[sp_metadata_acs]] SAML endpoint. Assertions using the HTTP-POST binding are
+<13> [[sp_metadata_acs]] SAML endpoint. Assertions using the HTTP-POST binding are
delivered to this URL location.
-<13> For indexed endpoints if `isDefault` is true then this is the
+<14> For indexed endpoints if `isDefault` is true then this is the
default endpoint to select. If no endpoint claims to be the default
then the first endpoint in the list is the default.
-<14> SAML endpoint. Assertions using the HTTP-Artifact binding are
+<15> SAML endpoint. Assertions using the HTTP-Artifact binding are
delivered to this URL location.
-<15> SAML endpoint. Assertions using the PAOS binding are delivered to
+<16> SAML endpoint. Assertions using the PAOS binding are delivered to
this URL location. PAOS is used the the Enhanced Client or Proxy
Profile (a.k.a. ECP).
@@ -1222,17 +1228,20 @@ authentication.
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
-
+
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
+ urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
+ urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
- Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+ Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
+
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="https://rhsso.example.com:8443/auth/realms/test/protocol/saml" />
@@ -1281,19 +1290,22 @@ sent to this URL location.
<9> SAML endpoint. Logout messages using the HTTP-Redirect binding are
sent to this URL location.
-<10> Zero or more `` elements enumerate the name
+<10> SAML endpoint. Logout messages using the HTTP-POST binding are
+sent to this URL location.
+
+<11> Zero or more `` elements enumerate the name
identifier formats supported by this entity. See <> for more
details.
-<11> SAML endpoint. `` messages using the HTTP-POST
+<12> SAML endpoint. `` messages using the HTTP-POST
binding are sent by the SP to this URL location to establish a Single
Sign-On Session.
-<12> SAML endpoint. `` messages using the HTTP-Redirect
+<13> SAML endpoint. `` messages using the HTTP-Redirect
binding are sent by the SP to this URL location to establish a Single
Sign-On Session.
-<13> SAML endpoint. `` messages using the SOAP
+<14> SAML endpoint. `` messages using the SOAP
binding are sent by the SP to this URL location to establish a Single
Sign-On Session.
@@ -1687,6 +1699,7 @@ Host: mellon.example.com
Endpoints:
SingleLogoutService (SOAP): https://mellon.example.com/mellon/logout
SingleLogoutService (HTTP-Redirect): https://mellon.example.com/mellon/logout
+SingleLogoutService (HTTP-POST): https://mellon.example.com/mellon/logout
AssertionConsumerService (HTTP-POST): https://mellon.example.com/mellon/postResponse
AssertionConsumerService (HTTP-Artifact): https://mellon.example.com/mellon/artifactResponse
AssertionConsumerService (PAOS): https://mellon.example.com/mellon/paosResponse
@@ -3075,6 +3088,9 @@ Service `Location` declarations in your SP metadata. See
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient