Validate received response.

git-svn-id: https://modmellon.googlecode.com/svn/trunk/mod_mellon2@99 a716ebb1-153a-0410-b759-cfb97c6a1b53
This commit is contained in:
olavmrk 2010-06-30 14:02:33 +00:00
parent ee3562ea9e
commit 000397a681
2 changed files with 197 additions and 0 deletions

View File

@ -31,6 +31,7 @@
#include <lasso/xml/saml-2.0/saml2_attribute.h>
#include <lasso/xml/saml-2.0/saml2_attribute_value.h>
#include <lasso/xml/saml-2.0/saml2_authn_statement.h>
#include <lasso/xml/saml-2.0/saml2_audience_restriction.h>
#include <lasso/xml/misc_text_node.h>
/* The following are redefined in ap_config_auto.h */

View File

@ -1094,6 +1094,170 @@ static apr_time_t am_parse_timestamp(request_rec *r, const char *timestamp)
}
/* Validate the subject on an Assertion.
*
* request_rec *r The current request. Used to log
* errors.
* LassoSaml2Assertion *assertion The assertion we will validate.
* const char *url The current URL.
*
* Returns:
* OK on success, HTTP_BAD_REQUEST on failure.
*/
static int am_validate_subject(request_rec *r, LassoSaml2Assertion *assertion,
const char *url)
{
apr_time_t now;
apr_time_t t;
LassoSaml2SubjectConfirmation *sc;
LassoSaml2SubjectConfirmationData *scd;
if (assertion->Subject == NULL) {
/* No Subject to validate. */
return OK;
}
if (assertion->Subject->SubjectConfirmation == NULL) {
/* No SubjectConfirmation. */
return OK;
}
sc = assertion->Subject->SubjectConfirmation;
if (sc->Method == NULL ||
strcmp(sc->Method, "urn:oasis:names:tc:SAML:2.0:cm:bearer")) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid Method in SubjectConfirmation.");
return HTTP_BAD_REQUEST;
}
scd = sc->SubjectConfirmationData;
if (scd == NULL) {
/* Nothing to verify. */
return OK;
}
now = apr_time_now();
if (scd->NotBefore) {
t = am_parse_timestamp(r, scd->NotBefore);
if (t == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid timestamp in NotBefore in SubjectConfirmationData.");
return HTTP_BAD_REQUEST;
}
if (t - 60000000 > now) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"NotBefore in SubjectConfirmationData was in the future.");
return HTTP_BAD_REQUEST;
}
}
if (scd->NotOnOrAfter) {
t = am_parse_timestamp(r, scd->NotOnOrAfter);
if (t == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid timestamp in NotOnOrAfter in SubjectConfirmationData.");
return HTTP_BAD_REQUEST;
}
if (now >= t + 60000000) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"NotOnOrAfter in SubjectConfirmationData was in the past.");
return HTTP_BAD_REQUEST;
}
}
if (scd->Recipient) {
if (strcmp(scd->Recipient, url)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Wrong Recipient in SubjectConfirmationData. Current URL is: %s",
url);
return HTTP_BAD_REQUEST;
}
}
return OK;
}
/* Validate the conditions on an Assertion.
*
* Parameters:
* request_rec *r The current request. Used to log
* errors.
* LassoSaml2Assertion *assertion The assertion we will validate.
* const char *providerID The providerID of the SP.
*
* Returns:
* OK on success, HTTP_BAD_REQUEST on failure.
*/
static int am_validate_conditions(request_rec *r,
LassoSaml2Assertion *assertion,
const char *providerID)
{
LassoSaml2Conditions *conditions;
apr_time_t now;
apr_time_t t;
GList *i;
LassoSaml2AudienceRestriction *ar;
conditions = assertion->Conditions;
if (conditions->Condition != NULL) {
/* This is a list of LassoSaml2ConditionAbstract - if it
* isn't empty, we have an unsupported condition.
*/
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Unsupported condition in Assertion.");
return HTTP_BAD_REQUEST;
}
now = apr_time_now();
if (conditions->NotBefore) {
t = am_parse_timestamp(r, conditions->NotBefore);
if (t == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid timestamp in NotBefore in Condition.");
return HTTP_BAD_REQUEST;
}
if (t - 60000000 > now) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"NotBefore in Condition was in the future.");
return HTTP_BAD_REQUEST;
}
}
if (conditions->NotOnOrAfter) {
t = am_parse_timestamp(r, conditions->NotOnOrAfter);
if (t == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid timestamp in NotOnOrAfter in Condition.");
return HTTP_BAD_REQUEST;
}
if (now >= t + 60000000) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"NotOnOrAfter in Condition was in the past.");
return HTTP_BAD_REQUEST;
}
}
for (i = g_list_first(conditions->AudienceRestriction); i != NULL;
i = g_list_next(i)) {
ar = i->data;
if (ar->Audience == NULL || strcmp(ar->Audience, providerID)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid Audience in Conditions. Should be: %s",
providerID);
return HTTP_BAD_REQUEST;
}
}
return OK;
}
/* This function sets the session expire timestamp based on NotOnOrAfter
* attribute of a condition element.
*
@ -1392,6 +1556,8 @@ static int add_attributes(am_cache_entry_t *session, request_rec *r,
static int am_handle_reply_common(request_rec *r, LassoLogin *login,
char *relay_state, char *saml_response)
{
char *url;
char *chr;
const char *name_id;
LassoSamlp2Response *response;
LassoSaml2Assertion *assertion;
@ -1401,6 +1567,12 @@ static int am_handle_reply_common(request_rec *r, LassoLogin *login,
int rc;
const char *idp;
url = am_reconstruct_url(r);
chr = strchr(url, '&');
if (chr) {
*chr = '\0';
}
dir_cfg = am_get_dir_cfg(r);
if(LASSO_PROFILE(login)->nameIdentifier == NULL) {
@ -1416,6 +1588,16 @@ static int am_handle_reply_common(request_rec *r, LassoLogin *login,
response = LASSO_SAMLP2_RESPONSE(LASSO_PROFILE(login)->response);
if (response->parent.Destination) {
if (strcmp(response->parent.Destination, url)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Invalid Destination on Response. Should be: %s",
url);
lasso_login_destroy(login);
return HTTP_BAD_REQUEST;
}
}
if (g_list_length(response->Assertion) == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"No Assertion in response.");
@ -1430,6 +1612,20 @@ static int am_handle_reply_common(request_rec *r, LassoLogin *login,
}
assertion = g_list_first(response->Assertion)->data;
rc = am_validate_subject(r, assertion, url);
if (rc != OK) {
lasso_login_destroy(login);
return rc;
}
rc = am_validate_conditions(r, assertion,
LASSO_PROVIDER(LASSO_PROFILE(login)->server)->ProviderID);
if (rc != OK) {
lasso_login_destroy(login);
return rc;
}
in_response_to = response->parent.InResponseTo;