summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--FAQ.rst230
-rw-r--r--Makefile.am8
-rwxr-xr-xautogen.sh5
-rwxr-xr-xbindings/python/tests/profiles_tests.py4
-rw-r--r--configure.ac5
-rw-r--r--docs/Makefile.am2
-rw-r--r--docs/reference/lasso/Makefile.am2
-rw-r--r--lasso.pc.in2
-rw-r--r--lasso/saml-2.0/logout.c3
-rw-r--r--lasso/utils.h3
-rw-r--r--lasso/xml/private.h1
-rw-r--r--lasso/xml/saml-2.0/saml2_key_info_confirmation_data_type.c3
-rw-r--r--lasso/xml/saml-2.0/samlp2_logout_request.c8
-rw-r--r--lasso/xml/saml-2.0/samlp2_manage_name_id_request.c18
-rw-r--r--lasso/xml/xml.c148
-rw-r--r--tests/basic_tests.c26
-rwxr-xr-xtools/git-version-gen225
-rw-r--r--website/web/index.xml2
18 files changed, 630 insertions, 65 deletions
diff --git a/FAQ.rst b/FAQ.rst
new file mode 100644
index 00000000..638482f2
--- /dev/null
+++ b/FAQ.rst
@@ -0,0 +1,230 @@
+Lasso FAQ
+=========
+
+Generalities
+------------
+
+1. What is Lasso ?
+
+ Lasso is a C library which implements the identity federation and single-sign
+ on protocol standards ID-FF 1.2 and SAML 2.0. It also implements attribute
+ exchange
+
+2. What does Lasso mean ?
+
+ Lasso is the acronym of Liberty Alliance Single Sign On.
+
+2. What is Liberty Alliance ?
+
+ It'a consortium built to propose a common XML standard for transmitting
+ information about authentication and identity, made in response to the
+ Microsoft Passport technology. It has since been dismantled and all its assets
+ are now managed by the Oasis standard body and the Kantara initiative.
+
+ The more recent standard coming from the initial Liberty Alliance initiative
+ is SAML 2.0.
+
+Use of the library
+------------------
+
+1. How to make a simple POST assertion consumer using Python ?
+
+Using Python&WSGI:
+
+.. code-block:: python
+
+ import sys
+ import lasso
+ from wsgiref.simple_server import make_server
+ import logging
+ import urlparse
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ sp_metadata_xml = '''<?xml version="1.0"?>
+ <EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ entityID="http://localhost:8081/metadata">
+ <SPSSODescriptor
+ AuthnRequestsSigned="true"
+ protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+
+ <AssertionConsumerService isDefault="true" index="0"
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+ Location="http://localhost:8081/singleSignOnPost" />
+ <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
+ </SPSSODescriptor>
+ <Organization>
+ <OrganizationName xml:lang="en">Example SAML 2.0 metadatas</OrganizationName>
+ </Organization>
+ </EntityDescriptor>'''
+
+ idp_metadata_xml = '''<?xml version="1.0"?>
+ <EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ entityID="http://localhost:3001/saml/metadata">
+
+
+ <IDPSSODescriptor
+ WantAuthnRequestsSigned="true"
+ protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+ <KeyDescriptor use="signing">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <KeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">
+ <RSAKeyValue>
+ <Modulus>4yalpsp9Sxlsj07PEI8jJxhSJdo4F0iW0H8u1dhwmsW5YQvRUw/yPlmC09q4WjImmnFVNCJarAOYeFgQCxfIoBasKNnUeBQpogo8W0Q/3mCuKl6lNSr/PIuxMVVNPDWmWkhHXJx/MVar2IREKa1P4jHL0Uxl69/idLwc7TtK1h8=</Modulus>
+ <Exponent>AQAB</Exponent>
+ </RSAKeyValue>
+ </KeyValue>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ <KeyDescriptor use="encryption">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <KeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">
+ <RSAKeyValue>
+ <Modulus>wLu5SdmwyS4o1On/aw4nElLGERFG931exvkzu0ewaM1/oUyD3dO7UC5xMGnPfc6IaH5BcJc3fLr6PJhX55ZrMR98ToPwoUFwuLKK43exwYBEBOOMe1CrCB/Bq+EH6/2sKNXKfgJqj06/3yzafLRiWpMxy2isllxMAvaZXrkpm4c=</Modulus>
+ <Exponent>AQAB</Exponent>
+ </RSAKeyValue>
+ </KeyValue>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ </IDPSSODescriptor>
+
+ </EntityDescriptor>
+ '''
+
+ def app(environ, start_response):
+ server = lasso.Server.newFromBuffers(sp_metadata_xml)
+ server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, idp_metadata_xml)
+ login = lasso.Login(server)
+ try:
+ data = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
+ qs = urlparse.parse_qs(data)
+ try:
+ login.processAuthnResponseMsg(qs['SAMLResponse'][0])
+ except (lasso.DsError, lasso.ProfileCannotVerifySignatureError):
+ raise Exception('Invalid signature')
+ except lasso.Error:
+ raise Exception('Misc error')
+ try:
+ login.acceptSso()
+ except lasso.Error:
+ raise Exception('Invalid assertion')
+ except Exception, e:
+ start_response('500 Internal Error', [('content-type', 'text/plain')],
+ sys.exc_info())
+ return ['Erreur: ', str(e)]
+ else:
+ start_response('200 Ok', [('content-type', 'text/plain')], sys.exc_info())
+ return ['You are identified as ', login.assertion.subject.nameId.content]
+
+ s = make_server('0.0.0.0', 8081, app)
+ s.serve_forever()
+
+2. How to make a simple POST assertion consumer using PHP5 ?
+
+Put the following content in a file named index.php:
+
+.. code-block:: php
+
+ <?
+ require "lasso.php";
+
+ $sp_metadata_xml = <<<'XML'
+ <?xml version="1.0"?>
+ <EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ entityID="http://yourdomain.com/index.php?metadata">
+ <SPSSODescriptor
+ AuthnRequestsSigned="true"
+ protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+
+ <AssertionConsumerService isDefault="true" index="0"
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+ Location="http://yourdomain.com/index.php?assertion_consumer" />
+ <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
+ </SPSSODescriptor>
+ <Organization>
+ <OrganizationName xml:lang="en">Example SAML 2.0 metadatas</OrganizationName>
+ </Organization>
+ </EntityDescriptor>
+ XML;
+
+ $idp_metadata_xml = <<<'XML'
+ <EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ entityID="http://localhost:3001/saml/metadata">
+
+
+ <IDPSSODescriptor
+ WantAuthnRequestsSigned="true"
+ protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+ <KeyDescriptor use="signing">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <KeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">
+ <RSAKeyValue>
+ <Modulus>4yalpsp9Sxlsj07PEI8jJxhSJdo4F0iW0H8u1dhwmsW5YQvRUw/yPlmC09q4WjImmnFVNCJarAOYeFgQCxfIoBasKNnUeBQpogo8W0Q/3mCuKl6lNSr/PIuxMVVNPDWmWkhHXJx/MVar2IREKa1P4jHL0Uxl69/idLwc7TtK1h8=</Modulus>
+ <Exponent>AQAB</Exponent>
+ </RSAKeyValue>
+ </KeyValue>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ <KeyDescriptor use="encryption">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <KeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">
+ <RSAKeyValue>
+ <Modulus>wLu5SdmwyS4o1On/aw4nElLGERFG931exvkzu0ewaM1/oUyD3dO7UC5xMGnPfc6IaH5BcJc3fLr6PJhX55ZrMR98ToPwoUFwuLKK43exwYBEBOOMe1CrCB/Bq+EH6/2sKNXKfgJqj06/3yzafLRiWpMxy2isllxMAvaZXrkpm4c=</Modulus>
+ <Exponent>AQAB</Exponent>
+ </RSAKeyValue>
+ </KeyValue>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ </IDPSSODescriptor>
+
+ </EntityDescriptor>
+ XML;
+
+ if (isset($_GET["metadata"])) {
+ header('Content-Type: text/xml');
+ echo $sp_metadata_xml;
+ exit(0);
+ }
+
+ if (isset($_GET["assertion_consumer"])) {
+ $server = LassoServer::newFromBuffers($sp_metadata_xml);
+ $server->addProviderFromBuffer(LASSO_PROVIDER_ROLE_IDP, $idp_metadata_xml);
+ $login = new LassoLogin($server);
+
+ function error($msg) {
+ header("HTTP/1.0 500 Internal Error");
+ ?> <h1>Erreur:</h1><pre> <? echo htmlentities($msg); ?></pre><?
+ exit(0);
+ }
+
+ try {
+ try {
+ $login->processAuthnResponseMsg($_POST["SAMLResponse"]);
+ } catch (LassoDsError $e) {
+ error('Invalid signature');
+ } catch (LassoProfileCannotVerifySignatureError $e) {
+ error('Invalid signature');
+ } catch (LassoError $e) {
+ error('Misc error, ' . $e);
+ }
+ try {
+ $login->acceptSso();
+ } catch (LassoError $e) {
+ error('Invalid assertion');
+ }
+ } catch (Exception $e) {
+ error('Unexpected error: ' . $e);
+ }
+ ?> You are identified as <? echo $login->assertion->subject->nameId->content;
+
+You must replace the ``$idp_metadata_xml`` variable by your identity provider metadata.
+You can indicate to your identity provider the URL
+http://yourdomain.com/index.php?metadata as the URL of your metadata file.
diff --git a/Makefile.am b/Makefile.am
index 3aecc4d5..caca2f7d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,7 +7,9 @@ SUBDIRS = lasso \
docs
EXTRA_DIST = COPYING lasso.pc.in lasso-src-config.in autogen.sh tools abi \
- lasso.doap README.JAVA README.WIN32 HACKING logos
+ lasso.doap README.JAVA README.WIN32 HACKING logos $(top_srcdir)/.version
+
+BUILT_SOURCES = $(top_srcdir)/.version
MAINTAINERCLEANFILES = \
Makefile.in \
@@ -36,5 +38,9 @@ dist-hook:
else \
echo A git clone is required to generate a ChangeLog >&2; \
fi
+ echo $(VERSION) > $(distdir)/.tarball-version
DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
+
+$(top_srcdir)/.version:
+ echo $(VERSION) > $@-t && mv $@-t $@
diff --git a/autogen.sh b/autogen.sh
index 0db8cce5..bef8222d 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -27,7 +27,10 @@ cd "$srcdir"
DIE=1
}
-if automake-1.11 --version < /dev/null > /dev/null 2>&1; then
+if automake-1.12 --version < /dev/null > /dev/null 2>&1; then
+ AUTOMAKE=automake-1.12
+ ACLOCAL=aclocal-1.12
+elif automake-1.11 --version < /dev/null > /dev/null 2>&1; then
AUTOMAKE=automake-1.11
ACLOCAL=aclocal-1.11
elif automake-1.10 --version < /dev/null > /dev/null 2>&1; then
diff --git a/bindings/python/tests/profiles_tests.py b/bindings/python/tests/profiles_tests.py
index 0068d841..e86a6195 100755
--- a/bindings/python/tests/profiles_tests.py
+++ b/bindings/python/tests/profiles_tests.py
@@ -35,6 +35,9 @@ if not '../.libs' in sys.path:
sys.path.insert(0, '../.libs')
import lasso
+import logging
+
+logging.basicConfig()
try:
@@ -482,6 +485,7 @@ class LogoutTestCase(unittest.TestCase):
'''Test parsing of a logout request with more than one session index'''
content = '''<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="xxxx" Version="2.0" IssueInstant="2010-06-14T22:00:00">
<saml:Issuer>me</saml:Issuer>
+ <saml:NameID>coin</saml:NameID>
<samlp:SessionIndex>id1</samlp:SessionIndex>
<samlp:SessionIndex>id2</samlp:SessionIndex>
<samlp:SessionIndex>id3</samlp:SessionIndex>
diff --git a/configure.ac b/configure.ac
index 894b6ab1..a088547c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@ dnl - Second number is the number of supported API versions where API version >
dnl first number.
dnl - Third number is the current API version implementation version number.
dnl See libtool explanations about current, age and release, later in this file.
-AC_INIT([lasso], 2.4.0, lasso-devel@lists.labs.libre-entreprise.org)
+AC_INIT([lasso], m4_esyscmd([tools/git-version-gen .tarball-version]), lasso-devel@lists.labs.libre-entreprise.org)
dnl Check if autoconf ver > 2.53
AC_PREREQ(2.53)
AC_CONFIG_MACRO_DIR([m4])
@@ -136,7 +136,6 @@ AC_CHECK_PROGS(PYTHON, python)
AC_CHECK_PROGS(SWIG, swig)
dnl Make sure we have an ANSI compiler
-AM_C_PROTOTYPES
test "z$U" != "z" && AC_MSG_ERROR(Compiler not ANSI compliant)
dnl Check for variadic macros
@@ -160,7 +159,7 @@ dnl ==========================================================================
changequote(<<, >>)dnl
VERSION_MAJOR=`echo $VERSION | $SED -e 's/^\([^\.]*\)\.\([^\.]*\)\.\(.*\)$/\1/'`
VERSION_MINOR=`echo $VERSION | $SED -e 's/^\([^\.]*\)\.\([^\.]*\)\.\(.*\)$/\2/'`
-VERSION_RELEASE=`echo $VERSION | $SED -e 's/^\([^\.]*\)\.\([^\.]*\)\.\(.*\)$/\3/'`
+VERSION_RELEASE=`echo $VERSION | $SED -e 's/^\([^\.]*\)\.\([^\.]*\)\.\([0-9]*\).*$/\3/'`
changequote([, ])dnl
VERSION_UNDERSCORED=`echo $VERSION | $SED -e 's/\./_/g'`
AC_SUBST(VERSION_UNDERSCORED)
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 49c40034..e7265177 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -5,6 +5,6 @@ SUBDIRS = lasso-book
if ENABLE_GTK_DOC
SUBDIRS += reference
else
-DIST_SUBDIRS = reference
+DIST_SUBDIRS = reference lasso-book
endif
diff --git a/docs/reference/lasso/Makefile.am b/docs/reference/lasso/Makefile.am
index 4713c3c7..ac8c5118 100644
--- a/docs/reference/lasso/Makefile.am
+++ b/docs/reference/lasso/Makefile.am
@@ -90,8 +90,6 @@ GTKDOC_LIBS= \
$(top_builddir)/lasso/liblasso.la \
$(LASSO_LIBS)
-EXTRA_DIST =
-
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make
diff --git a/lasso.pc.in b/lasso.pc.in
index 6cfc4a4b..a1a830a8 100644
--- a/lasso.pc.in
+++ b/lasso.pc.in
@@ -6,6 +6,6 @@ includedir=@includedir@
Name: lasso
Version: @VERSION@
Description: A free implementation of the Liberty Alliance specifications
-Requires: libxml-2.0 libxslt xmlsec1 glib-2.0 gobject-2.0
+Requires.private: libxml-2.0 libxslt xmlsec1 glib-2.0 gobject-2.0
Cflags: -I${includedir} @LASSO_PUB_CFLAGS@
Libs: -L${libdir} @LASSO_CORE_LIBS@
diff --git a/lasso/saml-2.0/logout.c b/lasso/saml-2.0/logout.c
index 2244d566..ab47e357 100644
--- a/lasso/saml-2.0/logout.c
+++ b/lasso/saml-2.0/logout.c
@@ -321,6 +321,9 @@ lasso_saml20_logout_build_response_msg(LassoLogout *logout)
LASSO_SAML2_STATUS_CODE_RESPONDER,
LASSO_SAML2_STATUS_CODE_REQUEST_DENIED));
}
+ } else {
+ lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(
+ profile, profile->response));
}
/* build logout response message */
diff --git a/lasso/utils.h b/lasso/utils.h
index d62d3cdb..9526e0ed 100644
--- a/lasso/utils.h
+++ b/lasso/utils.h
@@ -123,6 +123,9 @@
#define lasso_release_list(dest) \
lasso_release_full2(dest, g_list_free, GList*)
+#define lasso_release_slist(dest) \
+ lasso_release_full2(dest, g_slist_free, GSList*)
+
#define lasso_release_list_of_full(dest, free_function) \
{ \
GList **__tmp = &(dest); \
diff --git a/lasso/xml/private.h b/lasso/xml/private.h
index 629d6ca5..b1ec0979 100644
--- a/lasso/xml/private.h
+++ b/lasso/xml/private.h
@@ -62,6 +62,7 @@ typedef enum {
SNIPPET_ALLOW_TEXT = 1 << 26, /* allow text childs in list of nodes */
SNIPPET_KEEP_XMLNODE = 1 << 27, /* force keep xmlNode */
SNIPPET_PRIVATE = 1 << 28, /* means that the offset is relative to a private extension */
+ SNIPPET_MANDATORY = 1 << 29, /* means that the element cardinality is at least 1 */
} SnippetType;
typedef enum {
diff --git a/lasso/xml/saml-2.0/saml2_key_info_confirmation_data_type.c b/lasso/xml/saml-2.0/saml2_key_info_confirmation_data_type.c
index 901b709b..dbd0fb47 100644
--- a/lasso/xml/saml-2.0/saml2_key_info_confirmation_data_type.c
+++ b/lasso/xml/saml-2.0/saml2_key_info_confirmation_data_type.c
@@ -64,7 +64,8 @@ struct _LassoSaml2KeyInfoConfirmationDataTypePrivate {
static struct XmlSnippet schema_snippets[] = {
{ "KeyInfo", SNIPPET_LIST_NODES|SNIPPET_PRIVATE,
- G_STRUCT_OFFSET(LassoSaml2KeyInfoConfirmationDataTypePrivate, KeyInfo), "LassoDsKeyInfo", NULL, NULL},
+ G_STRUCT_OFFSET(LassoSaml2KeyInfoConfirmationDataTypePrivate, KeyInfo),
+ "LassoDsKeyInfo", LASSO_DS_PREFIX, LASSO_DS_HREF},
{NULL, 0, 0, NULL, NULL, NULL}
};
diff --git a/lasso/xml/saml-2.0/samlp2_logout_request.c b/lasso/xml/saml-2.0/samlp2_logout_request.c
index 947e0cd6..3d123d65 100644
--- a/lasso/xml/saml-2.0/samlp2_logout_request.c
+++ b/lasso/xml/saml-2.0/samlp2_logout_request.c
@@ -139,8 +139,16 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode)
int rc = 0;
xmlNode *child = NULL;
LassoSamlp2LogoutRequestPrivate *pv = NULL;
+ LassoSamlp2LogoutRequest *logout_request = (LassoSamlp2LogoutRequest*)node;
rc = parent_class->init_from_xml(node, xmlnode);
+ if ((logout_request->BaseID != 0) +
+ (logout_request->NameID != 0) +
+ (logout_request->EncryptedID != 0) != 1) {
+ error("samlp2:LogoutRequest needs one of BaseID, NameID or EncryptedID");
+ rc = 1;
+ }
+
if (rc == 0) {
pv = GET_PRIVATE(node);
diff --git a/lasso/xml/saml-2.0/samlp2_manage_name_id_request.c b/lasso/xml/saml-2.0/samlp2_manage_name_id_request.c
index 207f1444..678c6201 100644
--- a/lasso/xml/saml-2.0/samlp2_manage_name_id_request.c
+++ b/lasso/xml/saml-2.0/samlp2_manage_name_id_request.c
@@ -78,12 +78,30 @@ static struct XmlSnippet schema_snippets[] = {
/* instance and class init functions */
/*****************************************************************************/
+static LassoNodeClass *parent_class = NULL;
+
+static int
+init_from_xml(LassoNode *node, xmlNode *xmlnode)
+{
+ int rc = 0;
+ LassoSamlp2ManageNameIDRequest *nid_request = (LassoSamlp2ManageNameIDRequest*)node;
+
+ rc = parent_class->init_from_xml(node, xmlnode);
+ if ((nid_request->NameID != 0) +
+ (nid_request->EncryptedID != 0) != 1) {
+ error("samlp2:LogoutRequest needs one of BaseID, NameID or EncryptedID");
+ rc = 1;
+ }
+ return rc;
+}
static void
class_init(LassoSamlp2ManageNameIDRequestClass *klass)
{
LassoNodeClass *nclass = LASSO_NODE_CLASS(klass);
+ parent_class = g_type_class_peek_parent(klass);
+ klass->parent.parent.init_from_xml = init_from_xml;
nclass->node_data = g_new0(LassoNodeClassData, 1);
lasso_node_class_set_nodename(nclass, "ManageNameIDRequest");
lasso_node_class_set_ns(nclass, LASSO_SAML2_PROTOCOL_HREF, LASSO_SAML2_PROTOCOL_PREFIX);
diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c
index 4fe7a575..b7b29f95 100644
--- a/lasso/xml/xml.c
+++ b/lasso/xml/xml.c
@@ -1366,14 +1366,42 @@ is_snippet_type(struct XmlSnippet *snippet, SnippetType simple_type) {
}
static inline gboolean
+is_snippet_mandatory(struct XmlSnippet *snippet)
+{
+ return snippet->type & SNIPPET_MANDATORY ? TRUE : FALSE;
+}
+
+static inline gboolean
+is_snippet_multiple(struct XmlSnippet *snippet)
+{
+ switch (snippet->type & 0xff) {
+ case SNIPPET_LIST_XMLNODES:
+ case SNIPPET_LIST_CONTENT:
+ case SNIPPET_LIST_NODES:
+ case SNIPPET_EXTENSION:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static inline gboolean
node_match_snippet(xmlNode *parent, xmlNode *node, struct XmlSnippet *snippet)
{
+ gboolean rc = TRUE;
+
/* special case of ArtifactResponse */
- if (snippet->type & SNIPPET_ANY)
+ if (snippet->type & SNIPPET_ANY) {
return TRUE;
- return (lasso_strisequal(snippet->name, (char*)node->name)
- && ((!snippet->ns_uri && lasso_equal_namespace(parent->ns, node->ns)) ||
- (node->ns && lasso_strisequal((char*)node->ns->href, snippet->ns_uri))));
+ } else {
+ rc = rc && lasso_strisequal(snippet->name, (char*)node->name);
+ rc = rc &&
+ ((!snippet->ns_uri &&
+ lasso_equal_namespace(parent->ns, node->ns)) ||
+ (node->ns &&
+ lasso_strisequal((char*)node->ns->href, snippet->ns_uri)));
+ return rc;
+ }
}
/** FIXME: return a real error code */
@@ -1396,16 +1424,20 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
xmlAttr *attr = NULL;
GType g_type = 0;
LassoNodeClass *node_class;
+ gint rc = 0;
- if (! xmlnode)
- return 1;
+ if (! xmlnode) {
+ rc = 1;
+ goto cleanup;
+ }
node_class = class = LASSO_NODE_GET_CLASS(node);
/* No node_data no initialization possible */
if (! class->node_data) {
message(G_LOG_LEVEL_WARNING, "Class %s has no node_data so no initialization "
"is possible", G_OBJECT_CLASS_NAME(class));
- return 0;
+ rc = 1;
+ goto cleanup;
}
/* Collect special snippets like SNIPPET_COLLECT_NAMESPACES, SNIPPET_ANY, SNIPPET_ATTRIBUTE
@@ -1461,14 +1493,16 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
if (attr->ns && lasso_strisequal((char*)attr->name, "type") &&
lasso_strisequal((char*)attr->ns->href, LASSO_XSI_HREF)) {
char *colon = strchr((char*)content, ':');
- xmlNs *ns;
- *colon = '\0';
- ns = xmlSearchNs(NULL, xmlnode, content);
- *colon = ':';
- if (ns && lasso_strisequal((char*)ns->href, (char*)node_class->node_data->ns->href)
- && lasso_strisequal(&colon[1], node_class->node_data->node_name)) {
- lasso_release_xml_string(content);
- continue;
+ if (colon) {
+ xmlNs *ns;
+ *colon = '\0';
+ ns = xmlSearchNs(NULL, xmlnode, content);
+ *colon = ':';
+ if (ns && lasso_strisequal((char*)ns->href, (char*)node_class->node_data->ns->href)
+ && lasso_strisequal(&colon[1], node_class->node_data->node_name)) {
+ lasso_release_xml_string(content);
+ continue;
+ }
}
}
@@ -1558,28 +1592,54 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
xmlNode *first_child = NULL;
GList **list = NULL;
xmlChar *content = NULL;
+ gboolean match = FALSE;
+ struct XmlSnippet *matched_snippet = NULL;
- /* Find a matching snippet */
- while (class_iter && ! node_match_snippet(xmlnode, t, snippet)) {
- snippet++;
+#define ADVANCE \
+ snippet++; \
next_node_snippet(&class_iter, &snippet);
+#define ERROR \
+ error("Element %s:%s cannot be parsed", \
+ t->ns != NULL ? (char*)t->ns->prefix : "<noprefix>", \
+ t->name); \
+ rc = 1; \
+ goto cleanup;
+ /* Find a matching snippet */
+ while (class_iter && snippet) {
+ gboolean mandatory = is_snippet_mandatory(snippet);
+ gboolean multiple = is_snippet_multiple(snippet);
+
+ if ((match = node_match_snippet(xmlnode, t, snippet))) {
+ matched_snippet = snippet;
+ class = class_iter->data;
+ g_type = G_TYPE_FROM_CLASS(class);
+ value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
+ list = value;
+ if (! multiple) {
+ ADVANCE;
+ }
+ break;
+ } else {
+ if (mandatory) {
+ break;
+ } else {
+ ADVANCE;
+ }
+ }
}
- if (! class_iter) {
- /* If we cannot find one, terminate here. */
- break;
+ if (! match) {
+ ERROR;
}
- class = class_iter->data;
- g_type = G_TYPE_FROM_CLASS(class);
- value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
- list = value;
+#undef ADVANCE
+#undef ERROR
- if (snippet->offset || (snippet->type & SNIPPET_PRIVATE)) {
- switch (snippet->type & 0xff) {
+ if (matched_snippet->offset || (matched_snippet->type & SNIPPET_PRIVATE)) {
+ switch (matched_snippet->type & 0xff) {
case SNIPPET_LIST_NODES:
case SNIPPET_NODE:
subnode = lasso_node_new_from_xmlNode_with_type(t,
- snippet->class_name);
- if (is_snippet_type(snippet, SNIPPET_NODE)) {
+ matched_snippet->class_name);
+ if (is_snippet_type(matched_snippet, SNIPPET_NODE)) {
lasso_assign_new_gobject(*(LassoNode**)value, subnode);
} else {
lasso_list_add_new_gobject(*list, subnode);
@@ -1589,7 +1649,7 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
first_child = xmlSecGetNextElementNode(t->children);
if (first_child) {
subnode = lasso_node_new_from_xmlNode_with_type(first_child,
- snippet->class_name);
+ matched_snippet->class_name);
lasso_assign_new_gobject(*(LassoNode**)value, subnode);
}
break;
@@ -1603,8 +1663,8 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
case SNIPPET_CONTENT:
case SNIPPET_LIST_CONTENT:
content = xmlNodeGetContent(t);
- if (is_snippet_type(snippet, SNIPPET_CONTENT)) {
- snippet_set_value(node, class, snippet, content);
+ if (is_snippet_type(matched_snippet, SNIPPET_CONTENT)) {
+ snippet_set_value(node, class, matched_snippet, content);
} else { /* only list of string-like xsd:type supported */
lasso_list_add_string(*list, (char*)content);
}
@@ -1620,22 +1680,9 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
}
/* When creating a new LassoNode and option KEEP_XMLNODE is present,
* we attached the xmlNode to the LassoNode */
- if (subnode && (snippet->type & SNIPPET_KEEP_XMLNODE)) {
+ if (subnode && (matched_snippet->type & SNIPPET_KEEP_XMLNODE)) {
lasso_node_set_original_xmlnode(subnode, t);
}
- switch (snippet->type & 0xff) {
- case SNIPPET_NODE:
- case SNIPPET_NODE_IN_CHILD:
- case SNIPPET_XMLNODE:
- case SNIPPET_CONTENT:
- case SNIPPET_SIGNATURE:
- /* Only one node to read, advance ! */
- ++snippet;
- next_node_snippet(&class_iter, &snippet);
- break;
- default:
- break;
- }
} else {
g_assert_not_reached();
}
@@ -1681,7 +1728,8 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
"class %s",
t->ns ? t->ns->href : NULL, t->name,
g_type_name(G_TYPE_FROM_INSTANCE(node)));
- return 1;
+ rc = 1;
+ goto cleanup;
}
}
}
@@ -1735,8 +1783,9 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
lasso_release_xml_string(private_key_password);
lasso_release_xml_string(certificate);
}
-
- return 0;
+cleanup:
+ lasso_release_slist(class_list);
+ return rc;
}
#undef trace_snippet
@@ -2789,6 +2838,7 @@ lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, x
case SNIPPET_ANY:
case SNIPPET_KEEP_XMLNODE:
case SNIPPET_PRIVATE:
+ case SNIPPET_MANDATORY:
case SNIPPET_UNUSED1:
g_assert_not_reached();
}
diff --git a/tests/basic_tests.c b/tests/basic_tests.c
index 78c70d7b..27218177 100644
--- a/tests/basic_tests.c
+++ b/tests/basic_tests.c
@@ -137,6 +137,22 @@ START_TEST(test07_registry_functional_mapping)
}
END_TEST
+static struct XmlSnippet schema_snippets[] = {
+ {NULL, 0, 0, NULL, NULL, NULL}
+};
+
+static void
+class_init(LassoNodeClass *klass)
+{
+ LassoNodeClass *nclass = LASSO_NODE_CLASS(klass);
+
+ nclass->node_data = g_new0(LassoNodeClassData, 1);
+ lasso_node_class_set_nodename(nclass, "Assertion");
+ lasso_node_class_set_ns(nclass,LASSO_SAML2_ASSERTION_HREF, LASSO_SAML2_ASSERTION_PREFIX);
+ lasso_node_class_add_snippets(nclass, schema_snippets);
+
+}
+
START_TEST(test08_test_new_from_xmlNode)
{
static GType this_type = 0;
@@ -147,7 +163,7 @@ START_TEST(test08_test_new_from_xmlNode)
sizeof (LassoNodeClass),
NULL,
NULL,
- NULL,
+ (GClassInitFunc) class_init,
NULL,
NULL,
sizeof(LassoNode),
@@ -1495,24 +1511,24 @@ START_TEST(test10_test_alldumps)
lasso_release_string(node_dump);
lasso_release_gobject(node2);
lasso_release_gobject(node);
- node = LASSO_NODE(lasso_samlp2_logout_request_new());
+/* node = LASSO_NODE(lasso_samlp2_logout_request_new());
node_dump = lasso_node_dump(node);
fail_unless((node2 = lasso_node_new_from_dump(node_dump)) != NULL, "restoring dump failed after lasso_samlp2_logout_request_new");
lasso_release_string(node_dump);
lasso_release_gobject(node2);
- lasso_release_gobject(node);
+ lasso_release_gobject(node); */
node = LASSO_NODE(lasso_samlp2_logout_response_new());
node_dump = lasso_node_dump(node);
fail_unless((node2 = lasso_node_new_from_dump(node_dump)) != NULL, "restoring dump failed after lasso_samlp2_logout_response_new");
lasso_release_string(node_dump);
lasso_release_gobject(node2);
lasso_release_gobject(node);
- node = LASSO_NODE(lasso_samlp2_manage_name_id_request_new());
+/* node = LASSO_NODE(lasso_samlp2_manage_name_id_request_new());
node_dump = lasso_node_dump(node);
fail_unless((node2 = lasso_node_new_from_dump(node_dump)) != NULL, "restoring dump failed after lasso_samlp2_manage_name_id_request_new");
lasso_release_string(node_dump);
lasso_release_gobject(node2);
- lasso_release_gobject(node);
+ lasso_release_gobject(node); */
node = LASSO_NODE(lasso_samlp2_manage_name_id_response_new());
node_dump = lasso_node_dump(node);
fail_unless((node2 = lasso_node_new_from_dump(node_dump)) != NULL, "restoring dump failed after lasso_samlp2_manage_name_id_response_new");
diff --git a/tools/git-version-gen b/tools/git-version-gen
new file mode 100755
index 00000000..34682473
--- /dev/null
+++ b/tools/git-version-gen
@@ -0,0 +1,225 @@
+#!/bin/sh
+# Print a version string.
+scriptversion=2012-12-31.23; # UTC
+
+# Copyright (C) 2007-2013 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
+# It may be run two ways:
+# - from a git repository in which the "git describe" command below
+# produces useful output (thus requiring at least one signed tag)
+# - from a non-git-repo directory containing a .tarball-version file, which
+# presumes this script is invoked like "./git-version-gen .tarball-version".
+
+# In order to use intra-version strings in your project, you will need two
+# separate generated version string files:
+#
+# .tarball-version - present only in a distribution tarball, and not in
+# a checked-out repository. Created with contents that were learned at
+# the last time autoconf was run, and used by git-version-gen. Must not
+# be present in either $(srcdir) or $(builddir) for git-version-gen to
+# give accurate answers during normal development with a checked out tree,
+# but must be present in a tarball when there is no version control system.
+# Therefore, it cannot be used in any dependencies. GNUmakefile has
+# hooks to force a reconfigure at distribution time to get the value
+# correct, without penalizing normal development with extra reconfigures.
+#
+# .version - present in a checked-out repository and in a distribution
+# tarball. Usable in dependencies, particularly for files that don't
+# want to depend on config.h but do want to track version changes.
+# Delete this file prior to any autoconf run where you want to rebuild
+# files to pick up a version string change; and leave it stale to
+# minimize rebuild time after unrelated changes to configure sources.
+#
+# As with any generated file in a VC'd directory, you should add
+# /.version to .gitignore, so that you don't accidentally commit it.
+# .tarball-version is never generated in a VC'd directory, so needn't
+# be listed there.
+#
+# Use the following line in your configure.ac, so that $(VERSION) will
+# automatically be up-to-date each time configure is run (and note that
+# since configure.ac no longer includes a version string, Makefile rules
+# should not depend on configure.ac for version updates).
+#
+# AC_INIT([GNU project],
+# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
+# [bug-project@example])
+#
+# Then use the following lines in your Makefile.am, so that .version
+# will be present for dependencies, and so that .version and
+# .tarball-version will exist in distribution tarballs.
+#
+# EXTRA_DIST = $(top_srcdir)/.version
+# BUILT_SOURCES = $(top_srcdir)/.version
+# $(top_srcdir)/.version:
+# echo $(VERSION) > $@-t && mv $@-t $@
+# dist-hook:
+# echo $(VERSION) > $(distdir)/.tarball-version
+
+
+me=$0
+
+version="git-version-gen $scriptversion
+
+Copyright 2011 Free Software Foundation, Inc.
+There is NO warranty. You may redistribute this software
+under the terms of the GNU General Public License.
+For more information about these matters, see the files named COPYING."
+
+usage="\
+Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT]
+Print a version string.
+
+Options:
+
+ --prefix prefix of git tags (default 'v')
+ --fallback fallback version to use if \"git --version\" fails
+
+ --help display this help and exit
+ --version output version information and exit
+
+Running without arguments will suffice in most cases."
+
+prefix=v
+fallback=
+
+while test $# -gt 0; do
+ case $1 in
+ --help) echo "$usage"; exit 0;;
+ --version) echo "$version"; exit 0;;
+ --prefix) shift; prefix="$1";;
+ --fallback) shift; fallback="$1";;
+ -*)
+ echo "$0: Unknown option '$1'." >&2
+ echo "$0: Try '--help' for more information." >&2
+ exit 1;;
+ *)
+ if test "x$tarball_version_file" = x; then
+ tarball_version_file="$1"
+ elif test "x$tag_sed_script" = x; then
+ tag_sed_script="$1"
+ else
+ echo "$0: extra non-option argument '$1'." >&2
+ exit 1
+ fi;;
+ esac
+ shift
+done
+
+if test "x$tarball_version_file" = x; then
+ echo "$usage"
+ exit 1
+fi
+
+tag_sed_script="${tag_sed_script:-s/x/x/}"
+
+nl='
+'
+
+# Avoid meddling by environment variable of the same name.
+v=
+v_from_git=
+
+# First see if there is a tarball-only version file.
+# then try "git describe", then default.
+if test -f $tarball_version_file
+then
+ v=`cat $tarball_version_file` || v=
+ case $v in
+ *$nl*) v= ;; # reject multi-line output
+ [0-9]*) ;;
+ *) v= ;;
+ esac
+ test "x$v" = x \
+ && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2
+fi
+
+if test "x$v" != x
+then
+ : # use $v
+# Otherwise, if there is at least one git commit involving the working
+# directory, and "git describe" output looks sensible, use that to
+# derive a version string.
+elif test "`git log -1 --pretty=format:x . 2>&1`" = x \
+ && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \
+ || git describe --abbrev=4 HEAD 2>/dev/null` \
+ && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \
+ && case $v in
+ $prefix[0-9]*) ;;
+ *) (exit 1) ;;
+ esac
+then
+ # Is this a new git that lists number of commits since the last
+ # tag or the previous older version that did not?
+ # Newer: v6.10-77-g0f8faeb
+ # Older: v6.10-g0f8faeb
+ case $v in
+ *-*-*) : git describe is okay three part flavor ;;
+ *-*)
+ : git describe is older two part flavor
+ # Recreate the number of commits and rewrite such that the
+ # result is the same as if we were using the newer version
+ # of git describe.
+ vtag=`echo "$v" | sed 's/-.*//'`
+ commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \
+ || { commit_list=failed;
+ echo "$0: WARNING: git rev-list failed" 1>&2; }
+ numcommits=`echo "$commit_list" | wc -l`
+ v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
+ test "$commit_list" = failed && v=UNKNOWN
+ ;;
+ esac
+
+ # Change the first '-' to a '.', so version-comparing tools work properly.
+ # Remove the "g" in git describe's output string, to save a byte.
+ v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
+ v_from_git=1
+elif test "x$fallback" = x || git --version >/dev/null 2>&1; then
+ v=UNKNOWN
+else
+ v=$fallback
+fi
+
+v=`echo "$v" |sed "s/^$prefix//"`
+
+# Test whether to append the "-dirty" suffix only if the version
+# string we're using came from git. I.e., skip the test if it's "UNKNOWN"
+# or if it came from .tarball-version.
+if test "x$v_from_git" != x; then
+ # Don't declare a version "dirty" merely because a time stamp has changed.
+ git update-index --refresh > /dev/null 2>&1
+
+ dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty=
+ case "$dirty" in
+ '') ;;
+ *) # Append the suffix only if there isn't one already.
+ case $v in
+ *-dirty) ;;
+ *) v="$v-dirty" ;;
+ esac ;;
+ esac
+fi
+
+# Omit the trailing newline, so that m4_esyscmd can use the result directly.
+echo "$v" | tr -d "$nl"
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/website/web/index.xml b/website/web/index.xml
index 73059b9c..dab4af1f 100644
--- a/website/web/index.xml
+++ b/website/web/index.xml
@@ -22,7 +22,7 @@
We strongly recommend the use of the <a href="/license">GNU General Public
License</a> each time it is possible. But for proprietary projects, that
wouldn't want to use it, we designed a <a
- href="http://www.entrouvert.com/en/digital-identity/license-and-support">commercial
+ href="http://www.entrouvert.com/en/expertise/licenses/">commercial
license</a>.
</p>