profile: add two new class methods, lasso_profile_get_issuer and lasso_profile_get_in_response_to (#4378)
The goal of those two methods is to allow IdP and SP to load metadata dynamically without processing completely the incoming. Currently it's impossible as message parsing and signature checking is done in the same function.
This commit is contained in:
parent
67d0a0349d
commit
65bc705235
|
@ -54,6 +54,8 @@
|
|||
#endif
|
||||
#include "../lasso_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
/* public functions */
|
||||
/*****************************************************************************/
|
||||
|
@ -734,6 +736,119 @@ lasso_profile_get_signature_status(LassoProfile *profile)
|
|||
return profile->signature_status;
|
||||
}
|
||||
|
||||
static xmlChar *
|
||||
extract_issuer(xmlTextReader *reader)
|
||||
{
|
||||
const xmlChar *name;
|
||||
const xmlChar *ns_uri;
|
||||
xmlNode *node;
|
||||
|
||||
name = xmlTextReaderConstLocalName(reader);
|
||||
ns_uri = xmlTextReaderConstNamespaceUri(reader);
|
||||
|
||||
if (strcmp((const char*)name, "Issuer"))
|
||||
return NULL;
|
||||
if (strcmp((const char*)ns_uri, LASSO_SAML2_ASSERTION_HREF))
|
||||
return NULL;
|
||||
node = xmlTextReaderExpand(reader);
|
||||
return xmlNodeGetContent(node);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* lasso_profile_get_issuer:
|
||||
* @message: the HTTP query, POST content or SOAP message
|
||||
*
|
||||
* Extract the issuer of a message.
|
||||
*
|
||||
* Return value:(transfer full): Returns the issuer of the given message.
|
||||
*/
|
||||
char*
|
||||
lasso_profile_get_issuer(const char *message)
|
||||
{
|
||||
xmlTextReader *reader;
|
||||
char *result = NULL;
|
||||
int count = 0, ret;
|
||||
xmlChar *xml_result = NULL;
|
||||
xmlChar *to_free = NULL;
|
||||
|
||||
|
||||
reader = lasso_xmltextreader_from_message(message, &to_free);
|
||||
if (! reader)
|
||||
goto cleanup;
|
||||
ret = xmlTextReaderRead(reader);
|
||||
while (ret == 1) {
|
||||
int node_type = xmlTextReaderNodeType(reader);
|
||||
if (node_type == 1) {
|
||||
count += 1;
|
||||
xml_result = extract_issuer(reader);
|
||||
if (xml_result)
|
||||
break;
|
||||
}
|
||||
if (count == 3) {
|
||||
break;
|
||||
}
|
||||
ret = xmlTextReaderRead(reader);
|
||||
}
|
||||
if (! xml_result)
|
||||
goto cleanup;
|
||||
result = g_strdup((char *)xml_result);
|
||||
cleanup:
|
||||
if (xml_result)
|
||||
lasso_release_xml_string(xml_result);
|
||||
if (reader)
|
||||
xmlFreeTextReader(reader);
|
||||
if (to_free)
|
||||
lasso_release_xml_string(to_free);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* lasso_profile_get_request_id:
|
||||
* @message: the HTTP query, POST content or SOAP message
|
||||
*
|
||||
* Extract the issuer of a message.
|
||||
*
|
||||
* Return value:(transfer full): Returns the issuer of the given message.
|
||||
*/
|
||||
char*
|
||||
lasso_profile_get_in_response_to(const char *message)
|
||||
{
|
||||
xmlTextReader *reader;
|
||||
char *result = NULL;
|
||||
int ret;
|
||||
int node_type = 0;
|
||||
xmlChar *xml_result = NULL;
|
||||
xmlChar *to_free = NULL;
|
||||
|
||||
|
||||
reader = lasso_xmltextreader_from_message(message, &to_free);
|
||||
if (! reader)
|
||||
goto cleanup;
|
||||
ret = xmlTextReaderRead(reader);
|
||||
while (ret == 1) {
|
||||
node_type = xmlTextReaderNodeType(reader);
|
||||
if (node_type == 1) {
|
||||
break;
|
||||
}
|
||||
ret = xmlTextReaderRead(reader);
|
||||
}
|
||||
if (node_type != 1)
|
||||
goto cleanup;
|
||||
xml_result = xmlTextReaderGetAttribute(reader, BAD_CAST "InResponseTo");
|
||||
if (! xml_result)
|
||||
goto cleanup;
|
||||
result = g_strdup((char*)xml_result);
|
||||
cleanup:
|
||||
if (reader)
|
||||
xmlFreeTextReader(reader);
|
||||
if (xml_result)
|
||||
lasso_release_xml_string(xml_result);
|
||||
if (to_free)
|
||||
lasso_release_xml_string(to_free);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* overridden parent class methods */
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -211,6 +211,8 @@ LASSO_EXPORT LassoProfileSignatureVerifyHint lasso_profile_get_signature_verify_
|
|||
LASSO_EXPORT LassoProviderRole lasso_profile_sso_role_with(LassoProfile *profile,
|
||||
const char *remote_provider_id);
|
||||
LASSO_EXPORT lasso_error_t lasso_profile_get_signature_status(LassoProfile *profile);
|
||||
LASSO_EXPORT char* lasso_profile_get_issuer(const char *message);
|
||||
LASSO_EXPORT char* lasso_profile_get_in_response_to(const char *message);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -335,6 +335,8 @@ void lasso_xmlnode_add_saml2_signature_template(xmlNode *node, LassoSignatureCon
|
|||
|
||||
gchar* lasso_xmlnode_build_deflated_query(xmlNode *xmlnode);
|
||||
|
||||
xmlTextReader *lasso_xmltextreader_from_message(const char *message, xmlChar **to_free);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -1310,13 +1310,51 @@ lasso_get_query_string_param_value(const char *qs, const char *param_key, const
|
|||
}
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
lasso_inflate(unsigned char *input, size_t len)
|
||||
{
|
||||
z_stream zstr;
|
||||
unsigned char *output;
|
||||
int z_err;
|
||||
|
||||
zstr.zalloc = NULL;
|
||||
zstr.zfree = NULL;
|
||||
zstr.opaque = NULL;
|
||||
|
||||
output = g_malloc(len*10);
|
||||
zstr.avail_in = len;
|
||||
zstr.next_in = (unsigned char*)input;
|
||||
zstr.total_in = 0;
|
||||
zstr.avail_out = len*10;
|
||||
zstr.total_out = 0;
|
||||
zstr.next_out = output;
|
||||
|
||||
z_err = inflateInit2(&zstr, -MAX_WBITS);
|
||||
if (z_err != Z_OK) {
|
||||
message(G_LOG_LEVEL_CRITICAL, "Failed to inflateInit");
|
||||
lasso_release_string(output);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
z_err = inflate(&zstr, Z_FINISH);
|
||||
if (z_err != Z_STREAM_END) {
|
||||
message(G_LOG_LEVEL_CRITICAL, "Failed to inflate");
|
||||
inflateEnd(&zstr);
|
||||
lasso_release_string(output);
|
||||
return NULL;
|
||||
}
|
||||
output[zstr.total_out] = 0;
|
||||
inflateEnd(&zstr);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
lasso_node_init_from_deflated_query_part(LassoNode *node, char *deflate_string)
|
||||
{
|
||||
int len;
|
||||
xmlChar *b64_zre, *zre, *re;
|
||||
z_stream zstr;
|
||||
int z_err;
|
||||
xmlDoc *doc;
|
||||
xmlNode *root;
|
||||
|
||||
|
@ -1326,40 +1364,15 @@ lasso_node_init_from_deflated_query_part(LassoNode *node, char *deflate_string)
|
|||
len = xmlSecBase64Decode(b64_zre, zre, len*4);
|
||||
xmlFree(b64_zre);
|
||||
|
||||
zstr.zalloc = NULL;
|
||||
zstr.zfree = NULL;
|
||||
zstr.opaque = NULL;
|
||||
|
||||
zstr.avail_in = len;
|
||||
re = xmlMalloc(len*10);
|
||||
zstr.next_in = (xmlChar*)zre;
|
||||
zstr.total_in = 0;
|
||||
zstr.avail_out = len*10;
|
||||
zstr.total_out = 0;
|
||||
zstr.next_out = re;
|
||||
|
||||
z_err = inflateInit2(&zstr, -MAX_WBITS);
|
||||
if (z_err != Z_OK) {
|
||||
message(G_LOG_LEVEL_CRITICAL, "Failed to inflateInit");
|
||||
xmlFree(zre);
|
||||
xmlFree(re);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
z_err = inflate(&zstr, Z_FINISH);
|
||||
if (z_err != Z_STREAM_END) {
|
||||
message(G_LOG_LEVEL_CRITICAL, "Failed to inflate");
|
||||
inflateEnd(&zstr);
|
||||
xmlFree(zre);
|
||||
xmlFree(re);
|
||||
return FALSE;
|
||||
}
|
||||
re[zstr.total_out] = 0;
|
||||
inflateEnd(&zstr);
|
||||
re = lasso_inflate(zre, len);
|
||||
xmlFree(zre);
|
||||
|
||||
if (! re)
|
||||
return FALSE;
|
||||
|
||||
doc = lasso_xml_parse_memory((char*)re, strlen((char*)re));
|
||||
xmlFree(re);
|
||||
lasso_release_string(re);
|
||||
|
||||
root = xmlDocGetRootElement(doc);
|
||||
lasso_node_init_from_xml(node, root);
|
||||
lasso_release_doc(doc);
|
||||
|
@ -2826,3 +2839,75 @@ lasso_xmlnode_add_saml2_signature_template(xmlNode *node, LassoSignatureContext
|
|||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static char*
|
||||
get_saml_message(char **query_fields) {
|
||||
int i;
|
||||
char *field, *t;
|
||||
|
||||
for (i=0; (field=query_fields[i]); i++) {
|
||||
t = strchr(field, '=');
|
||||
if (t == NULL)
|
||||
continue;
|
||||
*t = 0;
|
||||
if (strcmp(field, LASSO_SAML2_FIELD_ENCODING) == 0) {
|
||||
return t+1;
|
||||
}
|
||||
if (strcmp(field, LASSO_SAML2_FIELD_REQUEST) == 0 || strcmp(field, LASSO_SAML2_FIELD_RESPONSE) == 0) {
|
||||
return t+1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* lasso_xmltextreader_from_message:
|
||||
* @message: the HTTP query, POST content or SOAP message
|
||||
*
|
||||
* Try to parse the passed message and create an xmlTextReader from it.
|
||||
*/
|
||||
xmlTextReader *
|
||||
lasso_xmltextreader_from_message(const char *message, xmlChar **to_free) {
|
||||
size_t len = strlen(message);
|
||||
char *needle;
|
||||
char **query_fields = NULL;
|
||||
char *decoded_message = NULL;
|
||||
xmlTextReader *reader = NULL;
|
||||
|
||||
if (message[0] != '<') {
|
||||
needle = strchr(message, '=');
|
||||
if (needle) {
|
||||
ptrdiff_t needle_pos = (needle-message);
|
||||
if (len - needle_pos > 2) { // query
|
||||
query_fields = urlencoded_to_strings(needle+1);
|
||||
message = get_saml_message(query_fields);
|
||||
if (! message)
|
||||
goto cleanup;
|
||||
len = strlen(message);
|
||||
}
|
||||
}
|
||||
if (is_base64(message)) {
|
||||
int rc;
|
||||
decoded_message = g_malloc(len);
|
||||
rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)decoded_message, len);
|
||||
if (rc < 0)
|
||||
goto cleanup;
|
||||
len = rc;
|
||||
message = (char*)lasso_inflate((unsigned char*) decoded_message, rc);
|
||||
lasso_release_string(decoded_message);
|
||||
if (! message)
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (message[0] == '<') // XML case
|
||||
reader = xmlReaderForMemory(message, len, "", NULL, XML_PARSE_NOENT |
|
||||
XML_PARSE_NONET);
|
||||
|
||||
cleanup:
|
||||
if (query_fields)
|
||||
lasso_release(query_fields);
|
||||
if (decoded_message && to_free)
|
||||
*to_free = BAD_CAST decoded_message;
|
||||
return reader;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ extern "C" {
|
|||
|
||||
#include <libxml/uri.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
#include "../export.h"
|
||||
#include "../errors.h"
|
||||
|
|
|
@ -2082,6 +2082,18 @@ START_TEST(test15_ds_key_info)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
/* test load federation */
|
||||
START_TEST(test16_test_get_issuer)
|
||||
{
|
||||
char *content = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
g_file_get_contents(TESTSDATADIR "/response-1", &content, &len, NULL);
|
||||
check_str_equals(lasso_profile_get_issuer(content), "gefssstg");
|
||||
check_str_equals(lasso_profile_get_in_response_to(content), "xx");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite*
|
||||
basic_suite()
|
||||
{
|
||||
|
@ -2101,6 +2113,7 @@ basic_suite()
|
|||
TCase *tc_load_metadata = tcase_create("Test loading a federation metadata file");
|
||||
TCase *tc_key = tcase_create("Test loading and manipulating LassoKey objects");
|
||||
TCase *tc_key_info = tcase_create("Test creating and dumping ds:KeyInfo nodes");
|
||||
TCase *tc_get_issuer = tcase_create("Test get_issuer and get_request_id");
|
||||
|
||||
suite_add_tcase(s, tc_server_load_dump_empty_string);
|
||||
suite_add_tcase(s, tc_server_load_dump_random_string);
|
||||
|
@ -2117,6 +2130,7 @@ basic_suite()
|
|||
suite_add_tcase(s, tc_load_metadata);
|
||||
suite_add_tcase(s, tc_key);
|
||||
suite_add_tcase(s, tc_key_info);
|
||||
suite_add_tcase(s, tc_get_issuer);
|
||||
|
||||
tcase_add_test(tc_server_load_dump_empty_string, test01_server_load_dump_empty_string);
|
||||
tcase_add_test(tc_server_load_dump_random_string, test02_server_load_dump_random_string);
|
||||
|
@ -2133,6 +2147,7 @@ basic_suite()
|
|||
tcase_add_test(tc_load_metadata, test13_test_lasso_server_load_metadata);
|
||||
tcase_add_test(tc_key, test14_lasso_key);
|
||||
tcase_add_test(tc_key_info, test15_ds_key_info);
|
||||
tcase_add_test(tc_get_issuer, test16_test_get_issuer);
|
||||
tcase_set_timeout(tc_load_metadata, 10);
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<samlp:Response IssueInstant="2009-04-20T14:31:31.917Z" ID="dzzfpt4zXBljkK2pummN8Ro2zo-" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">gefssstg</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion Version="2.0" IssueInstant="2009-04-20T14:31:31.972Z" ID="Zm9SHCgSkcP34HQTbn5ZOp6dQeB" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"><saml:Issuer>gefssstg</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<samlp:Response InResponseTo="xx" IssueInstant="2009-04-20T14:31:31.917Z" ID="dzzfpt4zXBljkK2pummN8Ro2zo-" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">gefssstg</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion Version="2.0" IssueInstant="2009-04-20T14:31:31.972Z" ID="Zm9SHCgSkcP34HQTbn5ZOp6dQeB" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"><saml:Issuer>gefssstg</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
||||
|
@ -54,4 +54,4 @@ oKYPjJxpj5sK9iB5yW8=
|
|||
</ds:RSAKeyValue>
|
||||
</ds:KeyValue>
|
||||
</ds:KeyInfo>
|
||||
</ds:Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">999999500</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2009-04-20T14:36:31.973Z" Recipient="https://wg.us.wrproxy.com/idpsso.php"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotOnOrAfter="2009-04-20T14:36:31.972Z" NotBefore="2009-04-20T14:26:31.972Z"><saml:AudienceRestriction><saml:Audience>Webroot</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2009-04-20T14:31:31.971Z" SessionIndex="Zm9SHCgSkcP34HQTbn5ZOp6dQeB"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="lastname"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">User</saml:AttributeValue></saml:Attribute><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="uid"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">999999500</saml:AttributeValue></saml:Attribute><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="firstname"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Test</saml:AttributeValue></saml:Attribute><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="mail"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">999999500@apctest.ge.com</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
|
||||
</ds:Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">999999500</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2009-04-20T14:36:31.973Z" Recipient="https://wg.us.wrproxy.com/idpsso.php"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotOnOrAfter="2009-04-20T14:36:31.972Z" NotBefore="2009-04-20T14:26:31.972Z"><saml:AudienceRestriction><saml:Audience>Webroot</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2009-04-20T14:31:31.971Z" SessionIndex="Zm9SHCgSkcP34HQTbn5ZOp6dQeB"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="lastname"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">User</saml:AttributeValue></saml:Attribute><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="uid"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">999999500</saml:AttributeValue></saml:Attribute><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="firstname"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Test</saml:AttributeValue></saml:Attribute><saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="mail"><saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">999999500@apctest.ge.com</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
|
||||
|
|
Loading…
Reference in New Issue