gsasl-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gsasl branch, master, updated. gsasl-1-7-2-3-gd62f4e2


From: Simon Josefsson
Subject: [SCM] GNU gsasl branch, master, updated. gsasl-1-7-2-3-gd62f4e2
Date: Tue, 03 Apr 2012 07:06:57 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gsasl".

http://git.savannah.gnu.org/cgit/gsasl.git/commit/?id=d62f4e29220cd329d0b165f745ac8f1fe9ce79f8

The branch, master has been updated
       via  d62f4e29220cd329d0b165f745ac8f1fe9ce79f8 (commit)
      from  90b8e5b312a8df9b60ed5b62f883c56dcb8f1c22 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit d62f4e29220cd329d0b165f745ac8f1fe9ce79f8
Author: Simon Josefsson <address@hidden>
Date:   Fri Mar 30 12:58:06 2012 +0200

    Add example SAML20 server.

-----------------------------------------------------------------------

Summary of changes:
 .gitignore                                         |    6 +
 configure.ac                                       |   24 ++-
 examples/Makefile.am                               |    2 +-
 examples/{openid20 => saml20}/Makefile.am          |   15 +-
 examples/saml20/README                             |  103 ++++++
 examples/saml20/gsasl-saml20-request.c             |  275 ++++++++++++++++
 examples/saml20/gsasl-saml20-sp.php                |  126 ++++++++
 .../saml20/idp.protectnetwork.org/idp-metadata.xml |  113 +++++++
 examples/saml20/openidp.feide.no/idp-metadata.xml  |   27 ++
 .../smtp-server-saml20.c}                          |  328 ++++++++++----------
 examples/saml20/sp-crt.pem                         |   20 ++
 examples/saml20/sp-key.pem                         |  157 ++++++++++
 examples/saml20/sp-metadata.xml                    |   71 +++++
 13 files changed, 1099 insertions(+), 168 deletions(-)
 copy examples/{openid20 => saml20}/Makefile.am (66%)
 create mode 100644 examples/saml20/README
 create mode 100644 examples/saml20/gsasl-saml20-request.c
 create mode 100644 examples/saml20/gsasl-saml20-sp.php
 create mode 100644 examples/saml20/idp.protectnetwork.org/idp-metadata.xml
 create mode 100644 examples/saml20/openidp.feide.no/idp-metadata.xml
 copy examples/{openid20/smtp-server-openid20.c => saml20/smtp-server-saml20.c} 
(64%)
 create mode 100644 examples/saml20/sp-crt.pem
 create mode 100644 examples/saml20/sp-key.pem
 create mode 100644 examples/saml20/sp-metadata.xml

diff --git a/.gitignore b/.gitignore
index 9c772ee..1a00ffc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -104,6 +104,12 @@ examples/openid20/.deps/
 examples/openid20/.libs/
 examples/openid20/smtp-server-openid20
 examples/openid20/smtp-server-openid20.o
+examples/saml20/.deps/
+examples/saml20/.libs/
+examples/saml20/gsasl-saml20-request
+examples/saml20/gsasl-saml20-request.o
+examples/saml20/smtp-server-saml20
+examples/saml20/smtp-server-saml20.o
 examples/server-xmpp-saml20
 examples/server-xmpp-saml20.o
 examples/smtp-server
diff --git a/configure.ac b/configure.ac
index 0dc92c3..db0e064 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,7 +61,7 @@ AC_MSG_CHECKING([if backwards compatibility code should be 
present])
 AC_MSG_RESULT($obsolete)
 AM_CONDITIONAL(OBSOLETE, test "$obsolete" = "yes")
 
-# Check for gnutls
+# Check for GnuTLS.
 AC_ARG_WITH(gnutls,
   AS_HELP_STRING([--without-gnutls], [disable GnuTLS support]),
        gnutls=$withval, gnutls=yes)
@@ -90,6 +90,18 @@ GTK_DOC_CHECK(1.1)
 gl_INIT
 AM_CONDITIONAL(WINDOWS, test "$gl_cv_func_wsastartup" = "yes")
 
+# Check for Lasso.  For examples/saml20/.
+AC_ARG_WITH(lasso,
+  AS_HELP_STRING([--without-lasso],
+                 [disable Lasso (used by examples/saml20/)]),
+  lasso=$withval, lasso=yes)
+if test "$lasso" != "no"; then
+  PKG_CHECK_MODULES(LASSO, lasso >= 2.2.1, [lasso=yes], [lasso=no])
+  AC_SUBST(LASSO_CFLAGS)
+  LASSO_CFLAGS=`echo $pkg_cv_LASSO_CFLAGS | sed -e 's,\\\\,,g'`
+fi
+AM_CONDITIONAL(LASSO, test "$lasso" = "yes")
+
 AC_ARG_ENABLE([gcc-warnings],
   [AS_HELP_STRING([--enable-gcc-warnings],
                  [turn on lots of GCC warnings (for developers)])],
@@ -143,6 +155,7 @@ AC_CONFIG_FILES([
   doc/reference/version.xml
   examples/Makefile
   examples/openid20/Makefile
+  examples/saml20/Makefile
   gl/Makefile
   gltests/Makefile
   po/Makefile.in
@@ -157,9 +170,14 @@ AC_MSG_NOTICE([summary of build options:
   Host type:          ${host}
   Install prefix:     ${prefix}
   Compiler:           ${CC}
-  Warning flags:      errors: ${WERROR_CFLAGS} warnings: ${WARN_CFLAGS}
+  Warning flags:      $gl_gcc_warnings
   Library types:      Shared=${enable_shared}, Static=${enable_static}
   Valgrind:           ${VALGRIND}
-  GnuTLS support:     $gnutls
   Obsolete functions: $obsolete
+  GnuTLS support:     $gnutls
+        CPPFLAGS:     $INCLIBGNUTLS
+           LDADD:     $LTLIBGNUTLS
+  Lasso support:      $lasso
+       CPPFLAGS:      $LASSO_CFLAGS
+          LDADD:      $LASSO_LIBS
 ])
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 6b601bb..05b71ed 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -16,7 +16,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-SUBDIRS = openid20
+SUBDIRS = openid20 saml20
 
 AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS)
 AM_CPPFLAGS = -I$(top_srcdir)/lib/src -I../lib/src
diff --git a/examples/openid20/Makefile.am b/examples/saml20/Makefile.am
similarity index 66%
copy from examples/openid20/Makefile.am
copy to examples/saml20/Makefile.am
index f93c55c..3d05a0d 100644
--- a/examples/openid20/Makefile.am
+++ b/examples/saml20/Makefile.am
@@ -17,11 +17,16 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS)
-AM_CPPFLAGS = -I$(top_srcdir)/lib/src -I$(top_builddir)/lib/src
-LDADD = $(top_builddir)/lib/src/libgsasl.la
+AM_CPPFLAGS = -I$(top_srcdir)/lib/src -I$(top_builddir)/lib/src \
+       $(LASSO_CFLAGS)
+LDADD = $(top_builddir)/lib/src/libgsasl.la $(LASSO_LIBS)
 
-EXTRA_DIST = README gsasl-openid20-redirect.php gsasl-openid20-rp.php
+EXTRA_DIST = README
+EXTRA_DIST += gsasl-saml20-sp.php
+EXTRA_DIST += sp-metadata.xml sp-key.pem sp-crt.pem
+EXTRA_DIST += openidp.feide.no/idp-metadata.xml
+EXTRA_DIST += idp.protectnetwork.org/idp-metadata.xml
 
-if !WINDOWS
-noinst_PROGRAMS = smtp-server-openid20
+if LASSO
+noinst_PROGRAMS = smtp-server-saml20 gsasl-saml20-request
 endif
diff --git a/examples/saml20/README b/examples/saml20/README
new file mode 100644
index 0000000..29b69b3
--- /dev/null
+++ b/examples/saml20/README
@@ -0,0 +1,103 @@
+GNU SASL examples/saml20/README -- Explanation of SMTP SAML 2.0 example.
+Copyright (C) 2012 Simon Josefsson
+See the end for copying conditions.
+
+This directory holds a GNU SASL example application that implements a
+SMTP server with SAML 2.0 authentication support.  The SAML
+implementation used is Lasso: http://lasso.entrouvert.org/
+
+It should be noted that this is just an example of how it could work.
+You don't need to implement it this way.  For example, sometimes
+having a Apache/PHP web server running is a problem.  Then you could
+use something like MicroHTTPD and implement everything in one process
+using Lasso in C.  Then you don't need any IPC stuff.  Also, you could
+also want to use another SAML implementation instead of Lasso.  The
+point of this example is just to proof that it works.
+
+Install the SAML SP:
+
+  The "gsasl-saml20-sp.php" script needs to be install so that it
+  reachable under some URL via a web server.  This is the
+  AssertionConsumerService (ACS) for the GNU SASL SP.  For example, on
+  interop.josefsson.org I make the ACS available as
+
+    http://interop.josefsson.org/gsasl-saml20-sp.php
+
+  by copying the file into
+
+    /var/www/gsasl-saml20-sp.php
+
+  Configure the tool by specifying the state and configuration
+  directories in a file called gsasl-saml20-config.php in the same
+  directory, like this:
+
+  echo '<?php $state_path = "/tmp/gsasl-saml20"; $cfg_path = 
"/etc/gsasl-saml20"; ?>' > /var/www/gsasl-saml20-config.php
+
+  Of course you can chose different paths, but then you need to update
+  the paths accordingly in the rest of this documentation.
+
+Create SAML SP configuration:
+
+  /etc/gsasl-saml20/sp-key.pem
+  /etc/gsasl-saml20/sp-crt.pem
+
+    This is a private key and certificate for your SP.  It can be
+    self-signed.  You may generate the files with GnuTLS like this:
+
+    certtool -p --outfile sp-key.pem
+    echo 'organization=My SP' > sp-crt.template
+    certtool --generate-self-signed --load-privkey sp-key.pem
+             --template sp-crt.template --outfile sp-crt.pem
+
+    Currently the private key is not used to sign requests.
+
+  /etc/gsasl-saml20/sp-metadata.xml
+
+    This is specific for your SP.  Use sp-metadata.xml as a starting
+    point if you are unsure, and use a text editor to modify it.  You
+    need to:
+
+      1) Change the entityID to something (the URL does not have to
+         resolve to anything, but should be unique to this SP).
+
+      2) Replace the ACS URL to point at your gsasl-saml20-sp.php.
+
+      3) Replace the certificate data (in two places) with the base64
+         data from sp-crt.pem.
+
+      4) Update with your contact information at the bottom.
+
+    You may want to make the SP metadata reachable over the web as
+    well, for example by doing:
+
+      ln -s /etc/gsasl-saml20/sp-metadata.xml /var/www/
+
+  /etc/gsasl-saml20/IDP/idp-metadata.xml
+
+    This is the XML metadata for each IdP.  Replace "IDP" in the
+    filename with the Identity Provider Identifier you expect users to
+    type.
+
+  /etc/gsasl-saml20/openidp.feide.no/idp-metadata.xml
+
+    Here we used Feide OpenIdP as an example.  The content of
+    idp-metadata.xml is retrieved from the IdP.  For Feide OpenIdP you
+    can retrieve it from the following URL:
+
+    https://openidp.feide.no/simplesaml/saml2/idp/metadata.php
+
+  /etc/gsasl-saml20/idp.protectnetwork.org/idp-metadata.xml
+
+    As the second test IdP we used Protect Network.  You can retrieve
+    the file from here:
+
+      http://www.protectnetwork.org/protectnetwork-metadata.xml
+
+    Lasso requires that the KeyDescriptor tags are qualified with
+    attributes use="signing" or use="encryption" respectively, so you
+    need to modify the file slightly.
+
+----------------------------------------------------------------------
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/examples/saml20/gsasl-saml20-request.c 
b/examples/saml20/gsasl-saml20-request.c
new file mode 100644
index 0000000..87286df
--- /dev/null
+++ b/examples/saml20/gsasl-saml20-request.c
@@ -0,0 +1,275 @@
+/* gsasl-saml20-request.c --- Generate SAML Request, for smtp-server-saml20.
+ * Copyright (C) 2012  Simon Josefsson
+ *
+ * This file is part of GNU SASL.
+ *
+ * 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/>.
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <lasso/lasso.h>
+#include <lasso/xml/saml-2.0/samlp2_authn_request.h>
+
+static void
+mkdir_state (const char *state_path)
+{
+  int rc;
+
+  rc = mkdir (state_path, 0770);
+  if (rc != 0 && errno != EEXIST)
+    {
+      perror ("mkdir");
+      exit (EXIT_FAILURE);
+    }
+}
+
+static void
+mkdir_session (const char *state_path, const char *id)
+{
+  char *tmp;
+  int rc;
+
+  rc = asprintf (&tmp, "%s/%s", state_path, id);
+  if (rc <= 0)
+    {
+      perror ("asprintf");
+      exit (EXIT_FAILURE);
+    }
+
+  rc = mkdir (tmp, 0770);
+  free (tmp);
+  if (rc != 0)
+    {
+      perror ("mkdir");
+      exit (EXIT_FAILURE);
+    }
+}
+
+static void
+write_file (const char *file, const char *data)
+{
+  FILE *fh;
+
+  fh = fopen (file, "w");
+  if (!fh)
+    {
+      perror ("fopen");
+      exit (EXIT_FAILURE);
+    }
+
+  if (fprintf (fh, "%s", data) <= 0)
+    {
+      perror ("fprintf");
+      exit (EXIT_FAILURE);
+    }
+
+  if (fclose (fh))
+    {
+      perror ("fclose");
+      exit (EXIT_FAILURE);
+    }
+}
+
+static void
+write_authreq (LassoLogin * login, const char *state_path, const char *id)
+{
+  LassoNode *authreq;
+  char *authreq_xml;
+  char *filename;
+  int rc;
+
+  authreq = LASSO_PROFILE (login)->request;
+  if (!authreq)
+    {
+      fprintf (stderr, "LASSO_PROFILE(login)->request\n");
+      exit (EXIT_FAILURE);
+    }
+
+  authreq_xml = lasso_node_export_to_xml (authreq);
+  if (!authreq_xml)
+    {
+      fprintf (stderr, "lasso_node_export_to_xml\n");
+      exit (EXIT_FAILURE);
+    }
+
+  rc = asprintf (&filename, "%s/%s/saml-request", state_path, id);
+  if (rc <= 0)
+    {
+      perror ("asprintf");
+      free (authreq_xml);
+      exit (EXIT_FAILURE);
+    }
+
+  write_file (filename, authreq_xml);
+
+  free (filename);
+  free (authreq_xml);
+}
+
+static void
+write_redirect_url (LassoLogin * login, const char *state_path,
+                   const char *id)
+{
+  char *filename;
+  int rc;
+
+  rc = asprintf (&filename, "%s/%s/redirect_url", state_path, id);
+  if (rc <= 0)
+    {
+      perror ("asprintf");
+      exit (EXIT_FAILURE);
+    }
+
+  write_file (filename, LASSO_PROFILE (login)->msg_url);
+
+  free (filename);
+}
+
+static void
+usage (const char *argv0)
+{
+  const char *progname = strrchr (argv0, '/') ?
+    1 + strrchr (argv0, '/') : argv0;
+
+  fprintf (stderr, "Usage: %s STATE-PATH SP-METADATA SP-KEY "
+          "SP-CRT IDP-METADATA\n", progname);
+  fprintf (stderr, "For example:\n");
+  fprintf (stderr, "   %s /tmp/gsasl-saml20 /path/to/sp-metadata.xml "
+          "/path/to/sp-key.pem /path/to/sp-crt.pem "
+          "/path/to/idp-metadata.xml\n", progname);
+}
+
+int
+main (int argc, char *argv[])
+{
+  const char *state_path, *spmetadata, *spkey, *spcrt, *idpmetadata, *idp;
+  LassoProvider *provider;
+  LassoServer *server;
+  LassoLogin *login;
+  LassoSamlp2AuthnRequest *request;
+  int rc;
+
+  if (argc != 6)
+    {
+      usage (argv[0]);
+      exit (EXIT_FAILURE);
+    }
+
+  state_path = argv[1];
+  spmetadata = argv[2];
+  spkey = argv[3];
+  spcrt = argv[4];
+  idpmetadata = argv[5];
+
+  mkdir_state (state_path);
+
+  rc = lasso_init ();
+  if (rc)
+    {
+      fprintf (stderr, "lasso_init (%d): %s\n", rc, lasso_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  provider = lasso_provider_new (LASSO_PROVIDER_ROLE_IDP,
+                                idpmetadata, NULL, NULL);
+  if (!provider)
+    {
+      fprintf (stderr, "%s", "lasso_provider_new");
+      exit (EXIT_FAILURE);
+    }
+
+  idp = provider->ProviderID;
+
+  server = lasso_server_new (spmetadata, spkey, NULL, spcrt);
+  if (!server)
+    {
+      fprintf (stderr, "%s", "lasso_server_new");
+      exit (EXIT_FAILURE);
+    }
+
+  rc = lasso_server_add_provider (server, LASSO_PROVIDER_ROLE_IDP,
+                                 idpmetadata, NULL, NULL);
+  if (rc)
+    {
+      fprintf (stderr, "lasso_server_add_provider (%d): %s\n",
+              rc, lasso_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  login = lasso_login_new (server);
+  if (!login)
+    {
+      fprintf (stderr, "%s", "lasso_login_new");
+      exit (EXIT_FAILURE);
+    }
+
+  rc = lasso_login_init_authn_request (login, idp,
+                                      LASSO_HTTP_METHOD_REDIRECT);
+  if (rc)
+    {
+      fprintf (stderr, "lasso_login_init_authn_request (%d): %s\n",
+              rc, lasso_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  request = LASSO_SAMLP2_AUTHN_REQUEST (LASSO_PROFILE (login)->request);
+
+  request->ForceAuthn = FALSE;
+  request->IsPassive = FALSE;
+
+  rc = lasso_login_build_authn_request_msg (login);
+  if (rc)
+    {
+      fprintf (stderr, "lasso_login_build_authn_request_msg (%d): %s\n",
+              rc, lasso_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  /* Populate session directory. */
+  mkdir_session (state_path, request->parent.ID);
+  write_authreq (login, state_path, request->parent.ID);
+  write_redirect_url (login, state_path, request->parent.ID);
+
+  /* Print session ID, this will enable the caller to find the session
+     information. */
+  if (puts (request->parent.ID) <= 0)
+    {
+      perror ("puts");
+      exit (EXIT_FAILURE);
+    }
+
+  /* We are done. */
+  lasso_login_destroy (login);
+  lasso_server_destroy (server);
+  /* lasso_provider_destroy (provider); */
+  rc = lasso_shutdown ();
+  if (rc)
+    {
+      fprintf (stderr, "lasso_shutdown (%d): %s\n", rc, lasso_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  exit (EXIT_SUCCESS);
+}
diff --git a/examples/saml20/gsasl-saml20-sp.php 
b/examples/saml20/gsasl-saml20-sp.php
new file mode 100644
index 0000000..8d86e0f
--- /dev/null
+++ b/examples/saml20/gsasl-saml20-sp.php
@@ -0,0 +1,126 @@
+<?php # -*- mode: php -*-
+
+// gsasl-saml20-sp.php --- SAML SP for smtp-server-saml20.c.
+// Copyright (C) 2012  Simon Josefsson
+//
+// This file is part of GNU SASL.
+//
+// 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/>.
+
+require "lasso.php";
+
+include "gsasl-saml20-config.php";
+
+if (!isset($state_path) || !isset($cfg_path) || !is_writable($state_path)) {
+  print "Error: Configuration error";
+  exit (0);
+}
+
+if (!isset($_POST["SAMLResponse"])) {
+  print "Error: Expected SAMLResponse POST data";
+  exit (0);
+}
+
+$xml = base64_decode($_POST["SAMLResponse"]);
+if (preg_match ("/<[^> ]+:Response[^>]+InResponseTo=\"([A-Za-z0-9_]+)\"/",
+               $xml, $matches) != 1) {
+  print "Error: Could not parse XML";
+  error_log ("parsing XML failed: $xml");
+  exit (0);
+}
+$id = $matches[1];
+if (!file_exists ("$state_path/$id") && !mkdir ("$state_path/$id", 0770)) {
+  error_log ("mkdir: $state_path/$id");
+  exit (0);
+}
+file_put_contents ("$state_path/$id/post", $xml);
+error_log ("saved SAMLResponse into $state_path/$id/post");
+
+function error($msg) {
+  global $state_path, $id;
+  file_put_contents ("$state_path/$id/fail", "");
+  print "Error: " . htmlentities($msg);
+  exit(0);
+}
+
+try {
+  $server = new LassoServer("$cfg_path/sp-metadata.xml",
+                           "$cfg_path/sp-key.pem", "",
+                           "$cfg_path/sp-crt.pem");
+  $idps = "";
+  foreach (glob("$cfg_path/*", GLOB_ONLYDIR) as $dir) {
+    if (is_readable ("$dir/idp-metadata.xml")) {
+      $idps .= " $dir/idp-metadata.xml";
+      $server->addProvider(LASSO_PROVIDER_ROLE_IDP, "$dir/idp-metadata.xml");
+    }
+  }
+  error_log ("IdPs:$idps");
+  $login = new LassoLogin($server);
+} catch (Exception $e) {
+  error('Unexpected Lasso error: ' . $e);
+  }
+
+try {
+  try {
+    $login->processAuthnResponseMsg($_POST["SAMLResponse"]);
+
+    $xml = new SimpleXMLElement($login->response->exportToXml());
+    $xml_id = $xml->attributes()->{'InResponseTo'};
+    if ($id != $xml_id) {
+      error_log ("ID parse error: guessed $id got $xml_id");
+    }
+
+    if (!file_exists ("$state_path/$id") && !mkdir ("$state_path/$id", 0770)) {
+      error ("State management failure (replay?)");
+    }
+
+    file_put_contents ("$state_path/$id/samlresp",
+                      $login->response->getXmlNode(false));
+  } catch (LassoDsError $e) {
+    error('Invalid signature');
+  } catch (LassoProfileCannotVerifySignatureError $e) {
+    error('Invalid signature');
+  } catch (LassoError $e) {
+    error('Misc error: ' . $e);
+  }
+  try {
+    $ok = $login->acceptSso();
+  } catch (LassoError $e) {
+    error('Invalid assertion');
+  }
+} catch (Exception $e) {
+  error('Unexpected error: ' . $e);
+}
+
+if ($ok != 0) {
+  error("acceptSso returned $ok");
+}
+
+file_put_contents ("$state_path/$id/subject",
+                  $login->assertion->subject->nameId->content);
+file_put_contents ("$state_path/$id/success", "");
+
+print "Congratulations!  You are authenticated as: "
+. $login->assertion->subject->nameId->content;
+
+print "\n\n<!--\n";
+print "\nDecrypted SAML Request:\n";
+print "\n";
+print $login->response->getXmlNode(false) . "\n";
+print "\nBase64-decoded POST Data:\n";
+print "\n";
+print base64_decode ($_POST["SAMLResponse"]) . "\n";
+print "\nEnd of data -->";
+
+?>
diff --git a/examples/saml20/idp.protectnetwork.org/idp-metadata.xml 
b/examples/saml20/idp.protectnetwork.org/idp-metadata.xml
new file mode 100644
index 0000000..ab5e827
--- /dev/null
+++ b/examples/saml20/idp.protectnetwork.org/idp-metadata.xml
@@ -0,0 +1,113 @@
+<EntityDescriptor entityID="https://idp.protectnetwork.org/protectnetwork-idp";
+                  xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+                  xmlns:ds="http://www.w3.org/2000/09/xmldsig#";
+                  xmlns:shibmd="urn:mace:shibboleth:metadata:1.0"
+                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
+
+    <IDPSSODescriptor protocolSupportEnumeration="urn:mace:shibboleth:1.0 
urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
+
+        <Extensions>
+            <shibmd:Scope regexp="false">idp.protectnetwork.org</shibmd:Scope>
+        </Extensions>
+
+        <KeyDescriptor use="signing">
+            <ds:KeyInfo>
+                <ds:X509Data>
+                    <ds:X509Certificate>
+MIICxzCCAjCgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkTELMAkGA1UEBhMCVVMx
+DjAMBgNVBAgTBVRleGFzMRcwFQYDVQQKEw45U3RhciBSZXNlYXJjaDEXMBUGA1UE
+CxMOUHJvdGVjdE5ldHdvcmsxGjAYBgNVBAMTEVByb3RlY3ROZXR3b3JrIENBMSQw
+IgYJKoZIhvcNAQkBFhVjYUBwcm90ZWN0bmV0d29yay5vcmcwHhcNMDcwMjE0MjA1
+ODA4WhcNMTcwMjExMjA1ODA4WjCBhzELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRl
+eGFzMQ8wDQYDVQQHEwZBdXN0aW4xHTAbBgNVBAoTFDlTdGFyIFJlc2VhcmNoLCBJ
+bmMuMRcwFQYDVQQLEw5Qcm90ZWN0TmV0d29yazEfMB0GA1UEAxMWaWRwLnByb3Rl
+Y3RuZXR3b3JrLm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDQt4HC/EHIKS8a
++Qd/4JE20wR91v5N7jh8ScDw6DvZ5RcvHQngXCk6FfCFUAev/dZxR31U4RpvFzCb
+j3sGB+G1AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T
+U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTRRyiPTvIDunJKy1+h
+mlkgl7/G+zAfBgNVHSMEGDAWgBQtFNiF4X/xTkU36JaWVCh08bzGgDANBgkqhkiG
+9w0BAQUFAAOBgQAm3BTIwg6Lxk3EAoLR2cDfb+jNWAtls7q077Mw3tMXxnuoi0uS
+o+LC6bPdPjC9YKujSKF34Au0s7y9bfXspClfCmyuviYVOrpVUze2h2MfHUVsKEUo
+/uivLYuMZjNp6Yrt90AoKPLPF6vU6gLAn6nsR7bhsdIqSXD/93r8HFV3NA==
+                    </ds:X509Certificate>
+                </ds:X509Data>
+            </ds:KeyInfo>
+        </KeyDescriptor>
+
+        <ArtifactResolutionService 
Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
+                                   
Location="https://idp.protectnetwork.org:8443/protectnetwork-idp/profile/SAML1/SOAP/ArtifactResolution";
+                                   index="1"/>
+
+        <ArtifactResolutionService 
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+                                   
Location="https://idp.protectnetwork.org:8443/protectnetwork-idp/profile/SAML2/SOAP/ArtifactResolution";
+                                   index="2"/>
+
+        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
+        
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+
+        <SingleSignOnService 
Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest"
+                             
Location="https://idp.protectnetwork.org/protectnetwork-idp/profile/Shibboleth/SSO";
 />
+
+        <SingleSignOnService 
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+                             
Location="https://idp.protectnetwork.org/protectnetwork-idp/profile/SAML2/POST/SSO";
 />
+
+        <SingleSignOnService 
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+                             
Location="https://idp.protectnetwork.org/protectnetwork-idp/profile/SAML2/POST-SimpleSign/SSO";
 />
+
+        <SingleSignOnService 
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+                             
Location="https://idp.protectnetwork.org/protectnetwork-idp/profile/SAML2/Redirect/SSO";
 />
+    </IDPSSODescriptor>
+
+    <AttributeAuthorityDescriptor 
protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol 
urn:oasis:names:tc:SAML:2.0:protocol">
+
+        <Extensions>
+            <shibmd:Scope regexp="false">idp.protectnetwork.org</shibmd:Scope>
+        </Extensions>
+
+        <KeyDescriptor use="encryption">
+            <ds:KeyInfo>
+                <ds:X509Data>
+                    <ds:X509Certificate>
+MIICxzCCAjCgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkTELMAkGA1UEBhMCVVMx
+DjAMBgNVBAgTBVRleGFzMRcwFQYDVQQKEw45U3RhciBSZXNlYXJjaDEXMBUGA1UE
+CxMOUHJvdGVjdE5ldHdvcmsxGjAYBgNVBAMTEVByb3RlY3ROZXR3b3JrIENBMSQw
+IgYJKoZIhvcNAQkBFhVjYUBwcm90ZWN0bmV0d29yay5vcmcwHhcNMDcwMjE0MjA1
+ODA4WhcNMTcwMjExMjA1ODA4WjCBhzELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRl
+eGFzMQ8wDQYDVQQHEwZBdXN0aW4xHTAbBgNVBAoTFDlTdGFyIFJlc2VhcmNoLCBJ
+bmMuMRcwFQYDVQQLEw5Qcm90ZWN0TmV0d29yazEfMB0GA1UEAxMWaWRwLnByb3Rl
+Y3RuZXR3b3JrLm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDQt4HC/EHIKS8a
++Qd/4JE20wR91v5N7jh8ScDw6DvZ5RcvHQngXCk6FfCFUAev/dZxR31U4RpvFzCb
+j3sGB+G1AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T
+U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTRRyiPTvIDunJKy1+h
+mlkgl7/G+zAfBgNVHSMEGDAWgBQtFNiF4X/xTkU36JaWVCh08bzGgDANBgkqhkiG
+9w0BAQUFAAOBgQAm3BTIwg6Lxk3EAoLR2cDfb+jNWAtls7q077Mw3tMXxnuoi0uS
+o+LC6bPdPjC9YKujSKF34Au0s7y9bfXspClfCmyuviYVOrpVUze2h2MfHUVsKEUo
+/uivLYuMZjNp6Yrt90AoKPLPF6vU6gLAn6nsR7bhsdIqSXD/93r8HFV3NA==
+                    </ds:X509Certificate>
+                </ds:X509Data>
+            </ds:KeyInfo>
+        </KeyDescriptor>
+
+        <AttributeService 
Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
+                          
Location="https://idp.protectnetwork.org:8443/protectnetwork-idp/profile/SAML1/SOAP/AttributeQuery";
 />
+
+        <AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+                          
Location="https://idp.protectnetwork.org:8443/protectnetwork-idp/profile/SAML2/SOAP/AttributeQuery";
 />
+
+        <NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
+        
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+
+    </AttributeAuthorityDescriptor>
+
+       <Organization>
+           <OrganizationName xml:lang="en">ProtectNetwork</OrganizationName>
+           <OrganizationDisplayName 
xml:lang="en">ProtectNetwork</OrganizationDisplayName>
+           <OrganizationURL 
xml:lang="en">http://www.protectnetwork.org</OrganizationURL>
+       </Organization>
+       <ContactPerson contactType="technical">
+               <GivenName>Todd</GivenName>
+           <SurName>Frankford</SurName>
+           <EmailAddress>address@hidden</EmailAddress>
+       </ContactPerson>
+
+</EntityDescriptor>
diff --git a/examples/saml20/openidp.feide.no/idp-metadata.xml 
b/examples/saml20/openidp.feide.no/idp-metadata.xml
new file mode 100644
index 0000000..54801df
--- /dev/null
+++ b/examples/saml20/openidp.feide.no/idp-metadata.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" 
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"; 
entityID="https://openidp.feide.no";>
+  <md:IDPSSODescriptor 
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+    <md:KeyDescriptor use="signing">
+      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#";>
+        <ds:X509Data>
+          
<ds:X509Certificate>MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==</ds:X509Certificate>
+        </ds:X509Data>
+      </ds:KeyInfo>
+    </md:KeyDescriptor>
+    <md:KeyDescriptor use="encryption">
+      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#";>
+        <ds:X509Data>
+          
<ds:X509Certificate>MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==</ds:X509Certificate>
+        </ds:X509Data>
+      </ds:KeyInfo>
+    </md:KeyDescriptor>
+    <md:SingleLogoutService 
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" 
Location="https://openidp.feide.no/simplesaml/saml2/idp/SingleLogoutService.php"/>
+    
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
+    <md:SingleSignOnService 
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" 
Location="https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php"/>
+  </md:IDPSSODescriptor>
+  <md:ContactPerson contactType="technical">
+    <md:GivenName>Feide</md:GivenName>
+    <md:SurName>support</md:SurName>
+    <md:EmailAddress>address@hidden</md:EmailAddress>
+  </md:ContactPerson>
+</md:EntityDescriptor>
diff --git a/examples/openid20/smtp-server-openid20.c 
b/examples/saml20/smtp-server-saml20.c
similarity index 64%
copy from examples/openid20/smtp-server-openid20.c
copy to examples/saml20/smtp-server-saml20.c
index f00cb29..b47718b 100644
--- a/examples/openid20/smtp-server-openid20.c
+++ b/examples/saml20/smtp-server-saml20.c
@@ -1,4 +1,4 @@
-/* smtp-server-openid20.c --- Example SMTP server with OpenID 2.0 support
+/* smtp-server-saml20.c --- Example SMTP server with SAML 2.0 support
  * Copyright (C) 2012  Simon Josefsson
  *
  * This file is part of GNU SASL.
@@ -20,7 +20,7 @@
 
 #include <config.h>
 
-/* This is based on ../smtp-server.c but adds support for OpenID 2.0.
+/* This is based on ../smtp-server.c but adds support for SAML 2.0.
    See README for instructions. */
 
 /* This is a minimal SMTP server with GNU SASL authentication support.
@@ -30,162 +30,151 @@
    specifying the service name (i.e., a numerical port number or
    /etc/services name).  By default it listens on port "2000".  */
 
-#include <stdio.h>
-#include <unistd.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <netdb.h>
 #include <signal.h>
+#include <time.h>
 
 #include <gsasl.h>
 
-static char *store_path;
-static char *realm;
-static char *return_to;
-
-static void
-hex_encode (char *dst, const char *src, size_t len)
+struct cfg
 {
-  static const char trans[] = "0123456789abcdef";
-
-  while (len--)
-    {
-      *dst++ = trans[(*src >> 4) & 0xf];
-      *dst++ = trans[*src++ & 0xf];
-    }
-
-  *dst = '\0';
-}
+  char *cfg_path;
+  char *state_path;
+  char *sp_metadata;
+  char *sp_key;
+  char *sp_cert;
+};
 
 static int
-write_file (const char *filename, const char *data)
+callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
 {
-  FILE *fh;
+  int rc = GSASL_NO_CALLBACK;
+  struct cfg *cfg = gsasl_callback_hook_get (ctx);
 
-  fh = fopen (filename, "w");
-  if (!fh)
+  switch (prop)
     {
-      perror ("fopen");
-      return -1;
-    }
-
-  if (fputs (data, fh) <= 0)
-    return -1;
-
-  if (fclose (fh) != 0)
-    return -1;
-
-  return 0;
-}
+    case GSASL_SAML20_REDIRECT_URL:
+      {
+       FILE *fh;
+       char *reqid, *redirect_url, *tmp;
+       size_t n = 0;
+       const char *idp =
+         gsasl_property_get (sctx, GSASL_SAML20_IDP_IDENTIFIER);
+
+       /* User did not provide a SAML IdP identifier. */
+       if (!idp)
+         return GSASL_AUTHENTICATION_ERROR;
+
+       /* Sanitize input. */
+       if (strcmp (idp, ".") == 0 || strcmp (idp, "..") == 0)
+         return GSASL_AUTHENTICATION_ERROR;
+       for (n = 0; idp[n]; n++)
+         if (!((idp[n] >= 'a' && idp[n] <= 'z')
+               || (idp[n] >= 'A' && idp[n] <= 'Z')
+               || (idp[n] >= '0' && idp[n] <= '9') || idp[n] == '.'))
+           {
+             printf ("Cannot handle identifier (%ld): %s\n", n, idp);
+             return GSASL_AUTHENTICATION_ERROR;
+           }
 
-static char *
-get_redirect_url (Gsasl_session * sctx)
-{
-  FILE *fh;
-  char *tmp, *tmp2;
-  char *line = NULL;
-  size_t n = 0;
-  const char *nonce = gsasl_session_hook_get (sctx);
-
-  asprintf (&tmp, "%s", store_path);
-  mkdir (tmp, 0770);
-  free (tmp);
-
-  asprintf (&tmp, "%s/state", store_path);
-  mkdir (tmp, 0770);
-  free (tmp);
-
-  asprintf (&tmp, "%s/state/%s", store_path, nonce);
-  mkdir (tmp, 0770);
-  free (tmp);
-
-  asprintf (&tmp, "%s/state/%s/openid_url", store_path, nonce);
-  if (write_file (tmp, gsasl_property_fast (sctx, GSASL_AUTHID)))
-    return NULL;
-  free (tmp);
-
-  asprintf (&tmp, "%s/state/%s/realm", store_path, nonce);
-  if (write_file (tmp, realm))
-    return NULL;
-  free (tmp);
-
-  asprintf (&tmp, "%s/state/%s/return_to", store_path, nonce);
-  asprintf (&tmp2, "%s/%s", return_to, nonce);
-  if (write_file (tmp, tmp2))
-    return NULL;
-  free (tmp);
-  free (tmp2);
-
-  asprintf (&tmp, "gsasl-openid20-redirect.php %s %s", store_path, nonce);
-  fh = popen (tmp, "r");
-  free (tmp);
-  if (!fh)
-    {
-      perror ("popen");
-      return NULL;
-    }
-  while (getline (&line, &n, fh) >= 0)
-    printf ("gsasl-openid20-redirect.php: %s", line);
-  pclose (fh);
+       /* Run helper to generate SAML AuthnRequest.   Read out request ID. */
+       rc = asprintf (&tmp, "gsasl-saml20-request %s %s %s %s "
+                      "%s/%s/idp-metadata.xml",
+                      cfg->state_path, cfg->sp_metadata,
+                      cfg->sp_key, cfg->sp_cert, cfg->cfg_path, idp);
+       if (rc <= 0)
+         return GSASL_AUTHENTICATION_ERROR;
+       fh = popen (tmp, "r");
+       free (tmp);
+       if (!fh)
+         {
+           perror ("popen");
+           return GSASL_AUTHENTICATION_ERROR;
+         }
+       reqid = NULL;
+       n = 0;
+       if (getline (&reqid, &n, fh) <= 0)
+         {
+           perror ("getline");
+           return GSASL_AUTHENTICATION_ERROR;
+         }
+       if (reqid[strlen (reqid) - 1] == '\n')
+         reqid[strlen (reqid) - 1] = '\0';
+       if (reqid[strlen (reqid) - 1] == '\r')
+         reqid[strlen (reqid) - 1] = '\0';
+       rc = pclose (fh);
+       if (rc != 0)
+         {
+           perror ("pclose");
+           return GSASL_AUTHENTICATION_ERROR;
+         }
 
-  asprintf (&tmp, "%s/state/%s/redirect_url", store_path, nonce);
-  fh = fopen (tmp, "r");
-  if (!fh)
-    {
-      perror ("fopen");
-      return NULL;
-    }
-  if (getline (&line, &n, fh) <= 0)
-    {
-      perror ("getline");
-      return NULL;
-    }
-  fclose (fh);
+       /* Read URL to redirect to.  Written by gsasl-saml20-request. */
+       rc = asprintf (&tmp, "%s/%s/redirect_url", cfg->state_path, reqid);
+       if (rc <= 0)
+         return GSASL_AUTHENTICATION_ERROR;
+       fh = fopen (tmp, "r");
+       free (tmp);
+       if (!fh)
+         {
+           perror ("fopen");
+           return GSASL_AUTHENTICATION_ERROR;
+         }
+       redirect_url = NULL;
+       n = 0;
+       if (getline (&redirect_url, &n, fh) <= 0)
+         {
+           perror ("getline");
+           return GSASL_AUTHENTICATION_ERROR;
+         }
+       rc = fclose (fh);
+       if (rc != 0)
+         {
+           perror ("fclose");
+           return GSASL_AUTHENTICATION_ERROR;
+         }
 
-  return line;
-}
+       /* We are done */
+       gsasl_session_hook_set (sctx, reqid);
+       gsasl_property_set (sctx, prop, redirect_url);
 
-static int
-callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
-{
-  int rc = GSASL_NO_CALLBACK;
-  FILE *fh;
-  char *line = NULL;
-  size_t n = 0;
-  const char *nonce = gsasl_session_hook_get (sctx);
-  char *tmp;
+       printf ("read id: %s\n", reqid);
+       printf ("url: %s\n", redirect_url);
 
-  switch (prop)
-    {
-    case GSASL_OPENID20_REDIRECT_URL:
-      {
-       line = get_redirect_url (sctx);
+       free (redirect_url);
 
-       gsasl_property_set (sctx, prop, line);
-       rc = GSASL_OK;
+       return GSASL_OK;
       }
       break;
 
-    case GSASL_VALIDATE_OPENID20:
+    case GSASL_VALIDATE_SAML20:
       {
        time_t start = time (NULL);
+       char *id = (char *) gsasl_session_hook_get (sctx);
+       char *tmp, *line;
+       size_t n;
+       FILE *fh;
+
+       if (!id)
+         return GSASL_AUTHENTICATION_ERROR;
 
-       rc = GSASL_AUTHENTICATION_ERROR;
        do
          {
            sleep (1);
-           
-           asprintf (&tmp, "%s/state/%s/success", store_path, nonce);
+
+           rc = asprintf (&tmp, "%s/%s/success", cfg->state_path, id);
+           if (rc <= 0)
+             return GSASL_AUTHENTICATION_ERROR;
            fh = fopen (tmp, "r");
            free (tmp);
            if (!fh)
              {
-               asprintf (&tmp, "%s/state/%s/fail", store_path, nonce);
+               rc = asprintf (&tmp, "%s/%s/fail", cfg->state_path, id);
+               if (rc <= 0)
+                 return GSASL_AUTHENTICATION_ERROR;
                fh = fopen (tmp, "r");
                free (tmp);
                if (!fh)
@@ -193,39 +182,64 @@ callback (Gsasl * ctx, Gsasl_session * sctx, 
Gsasl_property prop)
                    puts ("waiting");
                    continue;
                  }
+               rc = fclose (fh);
+               if (rc != 0)
+                 {
+                   perror ("fclose");
+                   return GSASL_AUTHENTICATION_ERROR;
+                 }
 
-               if (getline (&line, &n, fh) > 0)
-                 printf ("fail: %s\n", line);
-               fclose (fh);
-
-               rc = GSASL_AUTHENTICATION_ERROR;
-               break;
+               return GSASL_AUTHENTICATION_ERROR;
              }
 
-           if (getline (&line, &n, fh) > 0)
-             printf ("claimed id: %s\n", line);
-           fclose (fh);
+           rc = fclose (fh);
+           if (rc != 0)
+             {
+               perror ("fclose");
+               return GSASL_AUTHENTICATION_ERROR;
+             }
 
            gsasl_property_set (sctx, GSASL_AUTHID, line);
 
-           asprintf (&tmp, "%s/state/%s/sreg", store_path, nonce);
+           rc = asprintf (&tmp, "%s/%s/subject", cfg->state_path, id);
+           if (rc <= 0)
+             return GSASL_AUTHENTICATION_ERROR;
            fh = fopen (tmp, "r");
            free (tmp);
-           if (fh)
+           if (!fh)
              {
-               if (getline (&line, &n, fh) > 0)
-                 {
-                   printf ("sreg: %s\n", line);
-                   gsasl_property_set (sctx, GSASL_OPENID20_OUTCOME_DATA,
-                                       line);
-                 }
-               fclose (fh);
+               perror ("fopen");
+               return GSASL_AUTHENTICATION_ERROR;
+             }
+
+           line = NULL;
+           n = 0;
+           if (getline (&line, &n, fh) <= 0)
+             {
+               perror ("getline");
+               return GSASL_AUTHENTICATION_ERROR;
              }
 
-           rc = GSASL_OK;
-           break;
+           printf ("subject: %s\n", line);
+           gsasl_property_set (sctx, GSASL_AUTHID, line);
+           free (line);
+
+           rc = fclose (fh);
+           if (rc != 0)
+             {
+               perror ("fclose");
+               return GSASL_AUTHENTICATION_ERROR;
+             }
+
+           free (id);
+
+           return GSASL_OK;
          }
        while (time (NULL) - start < 30);
+
+       printf ("timeout\n");
+
+       return GSASL_AUTHENTICATION_ERROR;
       }
       break;
 
@@ -272,15 +286,6 @@ server_auth (FILE * fh, Gsasl_session * session)
   size_t n = 0;
   char *p;
   int rc;
-  /* The nonce value MUST be at least 2^32 large and large enough to
-     handle well in excess of the number of concurrent transactions a
-     SASL server shall see. */
-  char bin_nonce[32];
-  char nonce[2*sizeof(bin_nonce) + 1];
-
-  gsasl_nonce (bin_nonce, sizeof (bin_nonce));
-  hex_encode (nonce, bin_nonce, sizeof (bin_nonce));
-  gsasl_session_hook_set (session, nonce);
 
   /* The ordering and the type of checks in the following loop has to
      be adapted for each protocol depending on its SASL properties.
@@ -394,17 +399,21 @@ main (int argc, char *argv[])
   int rc;
   int yes = 1;
   Gsasl *ctx;
+  struct cfg cfg;
 
   setvbuf (stdout, NULL, _IONBF, 0);
 
-  if (argc != 5)
+  if (argc != 7)
     {
-      printf ("Usage: %s PORT STORE-PATH REALM RETURN-TO\n", argv[0]);
+      printf ("Usage: %s PORT CFG-PATH STATE-PATH SP-METADATA "
+             "SP-KEY SP-CERT\n", argv[0]);
       exit (EXIT_FAILURE);
     }
-  store_path = argv[2];
-  realm = argv[3];
-  return_to = argv[4];
+  cfg.cfg_path = argv[2];
+  cfg.state_path = argv[3];
+  cfg.sp_metadata = argv[4];
+  cfg.sp_key = argv[5];
+  cfg.sp_cert = argv[6];
 
   rc = gsasl_init (&ctx);
   if (rc < 0)
@@ -417,6 +426,7 @@ main (int argc, char *argv[])
          argv[0], GSASL_VERSION, gsasl_check_version (NULL));
 
   gsasl_callback_set (ctx, callback);
+  gsasl_callback_hook_set (ctx, &cfg);
 
   memset (&hints, 0, sizeof (hints));
   hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
diff --git a/examples/saml20/sp-crt.pem b/examples/saml20/sp-crt.pem
new file mode 100644
index 0000000..c4b168f
--- /dev/null
+++ b/examples/saml20/sp-crt.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVzCCAg+gAwIBAgIET3l7aTANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQKExpT
+aW1vbiBKb3NlZnNzb24gSW50ZXJvcCBTUDAeFw0xMjA0MDIxMDExNTNaFw0xMzA0
+MDIxMDExNTNaMCUxIzAhBgNVBAoTGlNpbW9uIEpvc2Vmc3NvbiBJbnRlcm9wIFNQ
+MIIBUjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKCATEA2kd6qFqmPTlXi24VbZtY
+HrOqhk9UNB7OoA+AVXhvHKO+5guhcxdhSxvQ/C1bAkytfhOqJut+6q93iiI+W2tj
+VCkT0UPyUNFHxlKJK3Y6ZG/W+andQOATWdCT6UCM278WYbBC+1xZqd/MGvxixFd/
+w+ZVDhaLmeRUbQfePQM6P0ksZoZh9Ctj2QMohEaJqiKsjsvQzSwBAi2GtxfMSiMB
+GUSKfseXclpziNsutsLuqbrKLRiZ/ts8GAJsQLkndGO054cbLX5Mx2/tYZR0FkK7
+uxfUWKleGIv6S76TTsOTZ+Afmv+R2jVLco1SbA2bvQ9OGhczByZTi3LtO2UzG5Ju
+yUFxZgpo30osNQIT4ZtggULX0BdABUmfrlYo+6fBIgsAYXWHxZjea2I9pCyb8gOa
+aQIDAQABoy8wLTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSf2/lube3cgv+IUz4O
+vLNDqwg5gTANBgkqhkiG9w0BAQsFAAOCATEAMzNcMklXduG1jevHvY4uL+G8dgFI
+9eBNTFkgbamJXqptEmGkCWOMMt8GSJoOjRtMbcxu7ao8wfBV7wRzk4ITpiB/IBqW
+dph9gNGDBasqnZxu+onh45BzGl3nY94aE2MfGS5FjxcGjYA5PJC/isNLlrJ1/YjO
+jYcDBcNRJvMXbDE13fY/vwKxLI1pdtpamys3Zogc3wzeuH5lLLB2blWS6eqwcnf4
+zNNFnusxOcOVt+DigN0otb+6V560mun6X+9vARIuEUHB1MNH7Y/mHy1T5CvZuyIw
+cgrfb2PocuvrkquzJPZCSJcsgzxLVFWXUr6hKhFoqh4nirrv5kfI8Ftm/hJxRBwE
+87Z2PnzISd4JQ20jbp2DEPJLYsWivKtJAWxZ4hfYc/SSKE39F7kwCWiwkQ==
+-----END CERTIFICATE-----
diff --git a/examples/saml20/sp-key.pem b/examples/saml20/sp-key.pem
new file mode 100644
index 0000000..eafc0b2
--- /dev/null
+++ b/examples/saml20/sp-key.pem
@@ -0,0 +1,157 @@
+Public Key Info:
+       Public Key Algorithm: RSA
+       Key Security Level: Normal
+
+modulus:
+       00:da:47:7a:a8:5a:a6:3d:39:57:8b:6e:15:6d:9b:
+       58:1e:b3:aa:86:4f:54:34:1e:ce:a0:0f:80:55:78:
+       6f:1c:a3:be:e6:0b:a1:73:17:61:4b:1b:d0:fc:2d:
+       5b:02:4c:ad:7e:13:aa:26:eb:7e:ea:af:77:8a:22:
+       3e:5b:6b:63:54:29:13:d1:43:f2:50:d1:47:c6:52:
+       89:2b:76:3a:64:6f:d6:f9:a9:dd:40:e0:13:59:d0:
+       93:e9:40:8c:db:bf:16:61:b0:42:fb:5c:59:a9:df:
+       cc:1a:fc:62:c4:57:7f:c3:e6:55:0e:16:8b:99:e4:
+       54:6d:07:de:3d:03:3a:3f:49:2c:66:86:61:f4:2b:
+       63:d9:03:28:84:46:89:aa:22:ac:8e:cb:d0:cd:2c:
+       01:02:2d:86:b7:17:cc:4a:23:01:19:44:8a:7e:c7:
+       97:72:5a:73:88:db:2e:b6:c2:ee:a9:ba:ca:2d:18:
+       99:fe:db:3c:18:02:6c:40:b9:27:74:63:b4:e7:87:
+       1b:2d:7e:4c:c7:6f:ed:61:94:74:16:42:bb:bb:17:
+       d4:58:a9:5e:18:8b:fa:4b:be:93:4e:c3:93:67:e0:
+       1f:9a:ff:91:da:35:4b:72:8d:52:6c:0d:9b:bd:0f:
+       4e:1a:17:33:07:26:53:8b:72:ed:3b:65:33:1b:92:
+       6e:c9:41:71:66:0a:68:df:4a:2c:35:02:13:e1:9b:
+       60:81:42:d7:d0:17:40:05:49:9f:ae:56:28:fb:a7:
+       c1:22:0b:00:61:75:87:c5:98:de:6b:62:3d:a4:2c:
+       9b:f2:03:9a:69:
+public exponent:
+       01:00:01:
+private exponent:
+       00:91:f0:22:70:f7:12:98:72:83:36:a4:a6:4c:ff:
+       04:be:9a:2f:13:d7:6c:1b:e0:d1:13:30:ea:03:bb:
+       1e:c6:ce:2f:ef:0c:ad:a8:0e:64:ad:5b:ee:b0:fb:
+       fe:12:1e:84:0c:7c:47:51:f8:37:85:df:45:14:24:
+       ea:fe:22:61:69:be:81:12:73:d4:49:f6:72:7f:85:
+       65:52:9a:9c:55:d4:74:ad:bd:c5:40:ff:cf:d0:47:
+       e4:ec:99:8c:d3:cb:01:c2:d4:9f:24:01:cd:ad:07:
+       05:26:b1:c1:b3:36:31:25:20:15:93:f2:bc:e9:6a:
+       40:8c:19:2b:9c:2d:51:3f:48:c4:17:d4:17:1f:b1:
+       f6:f2:fb:ea:95:ed:b7:52:fa:15:d6:ef:2c:2e:51:
+       12:67:8a:1e:a4:1f:7f:5b:c8:ef:bc:88:e5:91:da:
+       75:4e:fe:f7:2e:a6:6b:8e:1b:b1:d3:3c:e1:9d:84:
+       b4:ac:ca:3a:cd:3c:bb:a9:01:98:8c:07:b0:fc:9d:
+       60:3b:03:47:36:67:e8:ee:e5:61:8e:ca:29:ab:fb:
+       f4:6e:3f:1d:12:03:a5:f1:87:a0:3a:2e:5b:2a:22:
+       d0:b6:42:c9:d9:54:dd:1d:57:8b:28:e3:3a:d2:b7:
+       c0:ea:02:75:b1:28:88:38:6e:c8:f8:c6:93:f7:41:
+       ad:61:b3:22:88:4b:f3:5c:bc:44:d8:5b:d0:23:70:
+       6a:3c:80:db:c4:22:49:9b:11:7d:f7:ea:83:94:b2:
+       5f:c1:f6:98:77:a1:18:ee:c9:b6:31:ee:d2:5e:a7:
+       c7:7c:50:95:e5:
+prime1:
+       00:ec:b8:66:8f:f3:d6:d3:c5:2d:c0:b5:c7:3c:de:
+       02:b2:7f:71:14:bf:94:55:7b:b9:c0:2e:3e:1e:c1:
+       ad:26:31:60:46:ea:1f:2d:51:bf:81:ae:8c:f0:3a:
+       cb:a8:76:8e:12:38:8c:11:49:f8:32:68:01:15:ee:
+       09:e9:16:34:2e:31:f9:8d:1f:2e:11:57:f3:8a:b3:
+       1c:af:6e:33:0e:17:a8:1a:e0:d3:d4:4d:8f:7b:b8:
+       fc:d9:22:00:79:45:77:f3:84:32:59:9f:e8:19:00:
+       57:06:3e:ec:01:aa:55:f7:bf:f6:ee:5b:f7:67:3e:
+       97:db:8b:ad:81:f8:ce:8c:60:6b:19:fc:fe:df:8c:
+       8b:0e:a6:87:09:dc:34:71:ca:d2:f6:e9:e8:a2:94:
+       ad:32:53:
+prime2:
+       00:ec:0e:95:43:d1:d5:c9:ae:a4:ce:80:62:90:a3:
+       25:62:8d:ee:1a:f1:aa:4e:b4:bb:bf:81:e4:80:08:
+       63:4e:9d:f3:25:88:59:44:b4:80:de:d9:79:51:8f:
+       08:a7:4f:23:f6:37:cb:7c:b2:5d:25:da:ff:b2:da:
+       61:69:f5:d4:7b:5e:43:77:f3:a8:fd:9f:39:09:89:
+       ef:ad:c9:4a:9e:9b:98:d5:d4:e8:a6:ec:25:30:85:
+       45:84:63:c3:ca:4b:5c:7b:ed:f7:fb:72:45:d2:ba:
+       dc:8c:12:9a:5d:75:24:3e:86:a6:20:8d:f0:80:19:
+       7a:55:60:76:66:12:12:4a:50:95:dc:50:db:9a:5b:
+       38:0e:4c:72:6d:e7:69:ec:15:3e:e0:49:e0:f1:75:
+       8c:60:d3:
+coefficient:
+       74:ab:31:7b:a9:b5:c2:02:0a:a3:b9:02:c5:be:1e:
+       15:67:74:34:e7:b6:2a:33:61:0b:7d:f2:2a:e6:eb:
+       01:03:02:ad:13:b3:34:a9:b8:6f:8f:ea:2b:ed:74:
+       37:6a:fa:38:1c:c2:11:36:ba:46:f3:f9:e5:ee:f2:
+       55:05:41:7c:30:2d:e8:52:f9:9c:4f:d8:89:30:ae:
+       d5:b2:c8:0c:31:ef:94:73:20:aa:8c:43:60:41:f9:
+       5e:8f:7e:4b:e0:64:61:c2:d2:1a:fd:10:9e:09:2d:
+       d5:e0:15:48:f1:7e:17:3a:50:4e:6b:81:e1:a4:c9:
+       79:fc:88:75:51:36:ad:80:e4:41:4a:22:d2:05:a3:
+       df:38:a2:ba:e8:f5:2a:dc:c7:d9:2c:e1:8f:60:21:
+       ad:33:
+exp1:
+       00:9d:96:a1:08:a2:2e:d8:ea:42:6c:31:57:82:e8:
+       d5:68:d9:38:81:b4:8c:5e:60:30:a7:84:e1:6b:fe:
+       49:73:cc:99:28:7c:81:e6:dc:ae:1d:fa:02:ef:86:
+       64:c0:30:b4:a1:e2:ad:34:71:46:de:df:a8:21:5e:
+       47:90:b9:6c:61:78:79:86:7e:44:5f:dd:6a:4f:62:
+       af:ed:05:f2:cd:25:e8:8e:84:2f:e0:fd:05:51:3b:
+       34:70:a4:97:26:24:9e:17:2a:61:8e:92:ca:a3:a2:
+       3b:4c:f8:24:8b:73:47:29:d8:cc:dd:9f:b1:d3:34:
+       b3:49:bf:f1:f1:3d:9e:db:8a:f0:a1:eb:70:0d:88:
+       75:a6:7a:2c:19:df:53:b6:91:6c:e2:5d:93:b6:70:
+       3d:e0:eb:
+exp2:
+       49:39:08:d2:1d:bf:ec:2c:b1:50:a1:00:72:0f:39:
+       64:85:d4:2b:25:75:87:ae:86:62:94:3f:35:fb:e4:
+       1a:19:e2:b7:6c:c1:0c:0f:d5:bd:ca:c5:d8:27:bf:
+       2e:6e:dd:1f:de:14:cf:dc:60:0a:83:11:38:00:87:
+       a1:1f:b1:46:87:69:f4:46:6f:d0:24:58:c3:fd:b6:
+       8c:38:d9:5d:b3:b4:47:f8:20:26:cf:2f:86:0a:81:
+       12:dd:03:79:b7:c0:bb:6c:88:b4:c5:b0:a4:fa:73:
+       b9:3b:78:08:af:72:8b:b6:a6:c7:88:5f:e6:cc:80:
+       67:05:62:14:ad:5c:61:12:f8:39:7c:17:72:9d:03:
+       19:64:5b:46:7e:37:1c:15:47:08:b9:c1:fe:04:51:
+       84:23:
+
+Public Key ID: 9F:DB:F9:6E:6D:ED:DC:82:FF:88:53:3E:0E:BC:B3:43:AB:08:39:81
+Public key's random art:
++--[ RSA 2440]----+
+|                 |
+|                 |
+|                 |
+|     .           |
+|    E . S        |
+|       o . o. .  |
+|      +   o.o= ..|
+|       o . o*==o=|
+|        . address@hidden|
++-----------------+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIFfAIBAAKCATEA2kd6qFqmPTlXi24VbZtYHrOqhk9UNB7OoA+AVXhvHKO+5guh
+cxdhSxvQ/C1bAkytfhOqJut+6q93iiI+W2tjVCkT0UPyUNFHxlKJK3Y6ZG/W+and
+QOATWdCT6UCM278WYbBC+1xZqd/MGvxixFd/w+ZVDhaLmeRUbQfePQM6P0ksZoZh
+9Ctj2QMohEaJqiKsjsvQzSwBAi2GtxfMSiMBGUSKfseXclpziNsutsLuqbrKLRiZ
+/ts8GAJsQLkndGO054cbLX5Mx2/tYZR0FkK7uxfUWKleGIv6S76TTsOTZ+Afmv+R
+2jVLco1SbA2bvQ9OGhczByZTi3LtO2UzG5JuyUFxZgpo30osNQIT4ZtggULX0BdA
+BUmfrlYo+6fBIgsAYXWHxZjea2I9pCyb8gOaaQIDAQABAoIBMQCR8CJw9xKYcoM2
+pKZM/wS+mi8T12wb4NETMOoDux7Gzi/vDK2oDmStW+6w+/4SHoQMfEdR+DeF30UU
+JOr+ImFpvoESc9RJ9nJ/hWVSmpxV1HStvcVA/8/QR+TsmYzTywHC1J8kAc2tBwUm
+scGzNjElIBWT8rzpakCMGSucLVE/SMQX1Bcfsfby++qV7bdS+hXW7ywuURJnih6k
+H39byO+8iOWR2nVO/vcupmuOG7HTPOGdhLSsyjrNPLupAZiMB7D8nWA7A0c2Z+ju
+5WGOyimr+/RuPx0SA6Xxh6A6LlsqItC2QsnZVN0dV4so4zrSt8DqAnWxKIg4bsj4
+xpP3Qa1hsyKIS/NcvETYW9AjcGo8gNvEIkmbEX336oOUsl/B9ph3oRjuybYx7tJe
+p8d8UJXlAoGZAOy4Zo/z1tPFLcC1xzzeArJ/cRS/lFV7ucAuPh7BrSYxYEbqHy1R
+v4GujPA6y6h2jhI4jBFJ+DJoARXuCekWNC4x+Y0fLhFX84qzHK9uMw4XqBrg09RN
+j3u4/NkiAHlFd/OEMlmf6BkAVwY+7AGqVfe/9u5b92c+l9uLrYH4zoxgaxn8/t+M
+iw6mhwncNHHK0vbp6KKUrTJTAoGZAOwOlUPR1cmupM6AYpCjJWKN7hrxqk60u7+B
+5IAIY06d8yWIWUS0gN7ZeVGPCKdPI/Y3y3yyXSXa/7LaYWn11HteQ3fzqP2fOQmJ
+763JSp6bmNXU6KbsJTCFRYRjw8pLXHvt9/tyRdK63IwSml11JD6GpiCN8IAZelVg
+dmYSEkpQldxQ25pbOA5Mcm3naewVPuBJ4PF1jGDTAoGZAJ2WoQiiLtjqQmwxV4Lo
+1WjZOIG0jF5gMKeE4Wv+SXPMmSh8gebcrh36Au+GZMAwtKHirTRxRt7fqCFeR5C5
+bGF4eYZ+RF/dak9ir+0F8s0l6I6EL+D9BVE7NHCklyYknhcqYY6SyqOiO0z4JItz
+RynYzN2fsdM0s0m/8fE9ntuK8KHrcA2IdaZ6LBnfU7aRbOJdk7ZwPeDrAoGYSTkI
+0h2/7CyxUKEAcg85ZIXUKyV1h66GYpQ/NfvkGhnit2zBDA/VvcrF2Ce/Lm7dH94U
+z9xgCoMROACHoR+xRodp9EZv0CRYw/22jDjZXbO0R/ggJs8vhgqBEt0DebfAu2yI
+tMWwpPpzuTt4CK9yi7amx4hf5syAZwViFK1cYRL4OXwXcp0DGWRbRn43HBVHCLnB
+/gRRhCMCgZh0qzF7qbXCAgqjuQLFvh4VZ3Q057YqM2ELffIq5usBAwKtE7M0qbhv
+j+or7XQ3avo4HMIRNrpG8/nl7vJVBUF8MC3oUvmcT9iJMK7VssgMMe+UcyCqjENg
+Qflej35L4GRhwtIa/RCeCS3V4BVI8X4XOlBOa4HhpMl5/Ih1UTatgORBSiLSBaPf
+OKK66PUq3MfZLOGPYCGtMw==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/saml20/sp-metadata.xml b/examples/saml20/sp-metadata.xml
new file mode 100644
index 0000000..1244011
--- /dev/null
+++ b/examples/saml20/sp-metadata.xml
@@ -0,0 +1,71 @@
+<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+                    entityID="https://interop.josefsson.org/gsasl-saml20-sp";>
+  <md:SPSSODescriptor
+      protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+
+    <md:KeyDescriptor use="signing">
+      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#";>
+        <ds:X509Data>
+          <ds:X509Certificate>
+MIIDVzCCAg+gAwIBAgIET3l7aTANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQKExpT
+aW1vbiBKb3NlZnNzb24gSW50ZXJvcCBTUDAeFw0xMjA0MDIxMDExNTNaFw0xMzA0
+MDIxMDExNTNaMCUxIzAhBgNVBAoTGlNpbW9uIEpvc2Vmc3NvbiBJbnRlcm9wIFNQ
+MIIBUjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKCATEA2kd6qFqmPTlXi24VbZtY
+HrOqhk9UNB7OoA+AVXhvHKO+5guhcxdhSxvQ/C1bAkytfhOqJut+6q93iiI+W2tj
+VCkT0UPyUNFHxlKJK3Y6ZG/W+andQOATWdCT6UCM278WYbBC+1xZqd/MGvxixFd/
+w+ZVDhaLmeRUbQfePQM6P0ksZoZh9Ctj2QMohEaJqiKsjsvQzSwBAi2GtxfMSiMB
+GUSKfseXclpziNsutsLuqbrKLRiZ/ts8GAJsQLkndGO054cbLX5Mx2/tYZR0FkK7
+uxfUWKleGIv6S76TTsOTZ+Afmv+R2jVLco1SbA2bvQ9OGhczByZTi3LtO2UzG5Ju
+yUFxZgpo30osNQIT4ZtggULX0BdABUmfrlYo+6fBIgsAYXWHxZjea2I9pCyb8gOa
+aQIDAQABoy8wLTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSf2/lube3cgv+IUz4O
+vLNDqwg5gTANBgkqhkiG9w0BAQsFAAOCATEAMzNcMklXduG1jevHvY4uL+G8dgFI
+9eBNTFkgbamJXqptEmGkCWOMMt8GSJoOjRtMbcxu7ao8wfBV7wRzk4ITpiB/IBqW
+dph9gNGDBasqnZxu+onh45BzGl3nY94aE2MfGS5FjxcGjYA5PJC/isNLlrJ1/YjO
+jYcDBcNRJvMXbDE13fY/vwKxLI1pdtpamys3Zogc3wzeuH5lLLB2blWS6eqwcnf4
+zNNFnusxOcOVt+DigN0otb+6V560mun6X+9vARIuEUHB1MNH7Y/mHy1T5CvZuyIw
+cgrfb2PocuvrkquzJPZCSJcsgzxLVFWXUr6hKhFoqh4nirrv5kfI8Ftm/hJxRBwE
+87Z2PnzISd4JQ20jbp2DEPJLYsWivKtJAWxZ4hfYc/SSKE39F7kwCWiwkQ==
+         </ds:X509Certificate>
+        </ds:X509Data>
+      </ds:KeyInfo>
+    </md:KeyDescriptor>
+
+    <md:KeyDescriptor use="encryption">
+      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#";>
+        <ds:X509Data>
+          <ds:X509Certificate>
+MIIDVzCCAg+gAwIBAgIET3l7aTANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQKExpT
+aW1vbiBKb3NlZnNzb24gSW50ZXJvcCBTUDAeFw0xMjA0MDIxMDExNTNaFw0xMzA0
+MDIxMDExNTNaMCUxIzAhBgNVBAoTGlNpbW9uIEpvc2Vmc3NvbiBJbnRlcm9wIFNQ
+MIIBUjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKCATEA2kd6qFqmPTlXi24VbZtY
+HrOqhk9UNB7OoA+AVXhvHKO+5guhcxdhSxvQ/C1bAkytfhOqJut+6q93iiI+W2tj
+VCkT0UPyUNFHxlKJK3Y6ZG/W+andQOATWdCT6UCM278WYbBC+1xZqd/MGvxixFd/
+w+ZVDhaLmeRUbQfePQM6P0ksZoZh9Ctj2QMohEaJqiKsjsvQzSwBAi2GtxfMSiMB
+GUSKfseXclpziNsutsLuqbrKLRiZ/ts8GAJsQLkndGO054cbLX5Mx2/tYZR0FkK7
+uxfUWKleGIv6S76TTsOTZ+Afmv+R2jVLco1SbA2bvQ9OGhczByZTi3LtO2UzG5Ju
+yUFxZgpo30osNQIT4ZtggULX0BdABUmfrlYo+6fBIgsAYXWHxZjea2I9pCyb8gOa
+aQIDAQABoy8wLTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSf2/lube3cgv+IUz4O
+vLNDqwg5gTANBgkqhkiG9w0BAQsFAAOCATEAMzNcMklXduG1jevHvY4uL+G8dgFI
+9eBNTFkgbamJXqptEmGkCWOMMt8GSJoOjRtMbcxu7ao8wfBV7wRzk4ITpiB/IBqW
+dph9gNGDBasqnZxu+onh45BzGl3nY94aE2MfGS5FjxcGjYA5PJC/isNLlrJ1/YjO
+jYcDBcNRJvMXbDE13fY/vwKxLI1pdtpamys3Zogc3wzeuH5lLLB2blWS6eqwcnf4
+zNNFnusxOcOVt+DigN0otb+6V560mun6X+9vARIuEUHB1MNH7Y/mHy1T5CvZuyIw
+cgrfb2PocuvrkquzJPZCSJcsgzxLVFWXUr6hKhFoqh4nirrv5kfI8Ftm/hJxRBwE
+87Z2PnzISd4JQ20jbp2DEPJLYsWivKtJAWxZ4hfYc/SSKE39F7kwCWiwkQ==
+         </ds:X509Certificate>
+        </ds:X509Data>
+      </ds:KeyInfo>
+    </md:KeyDescriptor>
+
+    <md:AssertionConsumerService
+       Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+       Location="https://interop.josefsson.org/gsasl-saml20-sp.php";
+       index="0"/>
+  </md:SPSSODescriptor>
+
+  <md:ContactPerson contactType="technical">
+    <md:GivenName>Simon</md:GivenName>
+    <md:SurName>Josefsson</md:SurName>
+    <md:EmailAddress>address@hidden</md:EmailAddress>
+  </md:ContactPerson>
+</md:EntityDescriptor>


hooks/post-receive
-- 
GNU gsasl



reply via email to

[Prev in Thread] Current Thread [Next in Thread]