ZXID.org Identity Management toolkit implements standalone SAML 2.0 and Liberty ID-WSF 2.0 stacks and aims at implementing all popular federation and ID Web Services protocols. It is a C implementation with minimal external dependencies - OpenSSL, CURL, and zlib - ensuring easy deployment (no DLLhell). Due to its small footprint and efficient and accurate schema driven implementation, it is suitable for embedded and high volume applications. Language bindings to all popular highlevel languages such as PHP, Perl, and Java, are provided via SWIG. ZXID implements, as of July 07, SP, WSC, and WSP roles. IdP role will follow as the project evolves.
ZXID.org ist eine C-Bibliothek, die den vollständigen SAML 2.0-Stack implementiert und alle populären Identitätsverwaltungs-Protokolle wie Liberty ID-FF 1.2, WS-Federation, WS-Trust und ID-Webservices wie Liberty ID-WSF 1.1 und 2.0 implementieren will. Sie beruht auf Schema-basierter Code-Erzeugung, woraus eine genaue Implementation resultiert. SWIG wird verwendet, um Schnittstellen zu Skriptsprachen wie Perl, PHP und Python sowie zu Java bereitzustellen. Sie kann als SP, WSC und WSP fungieren. A biblioteca de gestão de identidades ZXID.org é uma implementação, em C, das normas SAML 2.0 e Liberty ID-WSF 2.0 com dependências externas mínimas - OpenSSL, CURL, e zlib - facilitando uma implantação fácil sem "inferno dos DLL". Sendo económica em consumo de recursos é indicada para aplicações embutidas ou de grande volume e performance. A biblioteca é disponibilizada para todos os linguagens de programação de alto nível como, p.ex., PHP, Perl, e Java, atravez de interfáces SWIG. ZXID de hoje (Jul 07) pode funcionar nos papeis SP (Provedor de Serviços), WSC (Cliente de Serviços Web) e WSP (Provedor de Serviços Web), sendo o papel IdP (Provedor de Identidade) suportado na futura evolução do projecto. La librería de gestión de identidades ZXID.org es una implementación en C de las normas SAML 2.0 y Liberty ID-WSF 2.0, con dependencias externas mínimas - OpenSSL, CURL, y zlib - que elimina el "Infierno DLL" en su implantación. Como ZXID es muy económica, es apta para aplicaciones embebidas o de gran volumen y envergadura. Los lenguajes de programación de alto nivel, como Perl, PHP, y Java, son soportados con generador de interfaces SWIG. Hoy (Feb 07) el ZXID soporta los roles SP (proveedor de servicios) y WSC (cliente de los servicios web). Los roles IdP (proveedor de identidades) y WSP (proveedor de servicios web) serán soportados en fases futuras del proyecto. ZXID.org on verkkohenkilöllisyyden ja -tunnisteiden hallintakirjasto joka tukee SAML 2.0 (sisäänkirjaantuminen) ja Liberty ID-WSF 2.0 (henkilöllisyyteen pohjautuvat webbipalvelut) standardeja. ZXID vaatii vain OpenSSL, CURL ja zlib kirjastot joten se välttää "DLL helvetti"-ongelman. Skemapohjaisena C toteutuksena se on tarkka ja taloudellinen ja kelpaa sulautettuihin ja erittäin kovaa suorituskykyä vaativiin sovelluksiin. Se tukee korkeantason kieliä - kuten Perliä, PHP:tä, ja Javaa - SWIG generoiduin rajapinnoin. ZXID tukee (Heinäkuu 07) SP (palveluntarjoaja), WSC (webbipalvelunkutsuja), ja WSP (webbipalveluntarjoaja) rooleja. IdP (henkilöllisyydenvarmentaja) rooli toteutetaan projektin tulevissa vaiheissa.
ZXID project has currently (Jan 2007) five outputs
A C library for supporting SAML 2.0, including federated Single Sign-On (SSO)
A C program that implements a SAML Service Provider (SP) as a CGI script
A Perl module wrapping libzxid. Also zxid.pl, that implements SP in mod_perl environment, is supplied.
A PHP extension that wraps libzxid. Also supplied: zxid.php that implements SP in mod_php environment.
A Java JNI extension that wraps libzxid. Also supplied: zxid.java that implements SP as a CGI script.
You need this if you are
You want to enable SAML based Single Sign-On (SSO) to your web site. In this case you would use the zxid SP CGI script directly, only configuring it slightly or you can go the zxid_simple() route. Otherwise you can hint your PHP or perl developer that this functionality is available and your want it.
You can use the Net::SAML module to integrate SSO to your application and web site. Given the direct perl support, this is easier than fully understanding the C interface. Both mod_perl and perl as CGI are supported.
You can use dl("php_zxid.so") to load the module and access the high level functionality, such as SAML 2.0 SSO. We support functionality roughly equivalent to perl Net::SAML. The PHP module is fully ready to use for SSO, but we expect to add a lot more, such as WSC, in future. Both mod_php5 and php as CGI are supported. php4 should also work.
You can use System.loadLibrary("zxidjni") to pull into your Java proram the full power of the ZXID. The functionality supported is roughly equal to Net::SAML.
You want to integrate SAML based SSO to your web site tool or product so that your customers can enjoy SSO enabled web sites. In this case you would study zxid.c for examples and use libzxid.a to implement the functionality in your own program.
You need some building blocks: you will study libzxid and add to it, contributing to the project.
ZXID Project has vastly more ambitious goals. See the ZXID Project chapter later in this document.
Conor Cahill of Intel (formerly AOL) said back in 2006:
IMNSHO, better go Liberty up front and have the confidence that you do not need to upgrade later - or run two parallel systems. The Liberty (or SAML 2.0) system is comprehensive and addresses every use case anyone has thought so far. The percieved complexity is really an implementation issue and not underlying propery of the spec. Since we provide an implementation, the "complexity" is not customer problem.
If you want to try ZXID out immediately, we recommend compiling the library and examples and installing one of the examples as a CGI script in an existing web server. See later chapters for more details.
tar xvzf zxid-0.15.tgz cd zxid-0.15 # N.B. There is no configure script. The Makefile works for all # supported platforms by provision of correct TARGET option. # N.B2: We distribute some generated files. If they are missing, you need # to regenerate them: make cleaner; make dep ENA_GEN=1 # Standard place is /var/zxid. You can change this with # make ZXID_PATH=/usr/local/var make # default Linux. Do `make TARGET=sol8' for Solaris make dir # Creates /var/zxid hierarchy (may need to be root) make samlmod # optional make samlmod_install # optional: install Net::SAML perl module make phpzxid # optional make phpzxid_install # optional: install php_zxid.so PHP extension make javazxid # optional cp zxid <webroot>/ # configure your web server to recognize zxid a CGI, e.g. mini_httpd -p 8443 -c 'zxid*' -S -E zxid.pem # Edit your /etc/hosts to contain 127.0.0.1 localhost sp1.zxidcommon.org sp1.zxidsp.org # Point your browser to (zxid_simple() API version) https://sp1.zxidsp.org:8443/zxidhlo?o=E https://sp1.zxidsp.org:8443/zxidhlo.pl?o=E # Perl version https://sp1.zxidsp.org:8443/zxidhlo.php?o=E # PHP version http://sp1.zxidsp.org:8080/zxidservlet/zxidHLO?o=E # Java version # Point your browser to (full API version) https://sp1.zxidsp.org:8443/zxid?o=E https://sp1.zxidsp.org:8443/zxid.pl?o=E # Perl version https://sp1.zxidsp.org:8443/zxid.php?o=E # PHP version https://sp1.zxidsp.org:8443/zxid-java.sh?o=E # Java version # Find an IdP to test with and configure it...
This software depends on the following packages:
zlib from zlib.net. Generally whatever comes with your distro is sufficient.
openssl-0.9.8d or later. See www.openssl.org. Generally openssl libraries distributed with most Linux distros are sufficient.
libcurl from http://curl.haxx.se/. I used version 7.15.5, but probably whatever ships with your distribution is fine. libcurl is needed
for SOAP bindings and for fetching metadata. It needs to be compiled
to support HTTPS.
HTTPS capable web server. For most trivial testing CGI support is needed. We recommend mini_httpd(8) available from http://www.acme.com/software/mini_httpd/
Perl, PHP, and Java interfaces depend on the respective development tools but should not need any additional modules or tools.
Following additional packages are needed by developers who wish to build from scratch, including the code generation (the standard distribution includes the output of the code generation, so most people do not need these).
gperf from gnu.org (only for build process when generating code)
swig from swig.org (only for build process and only if you want scripting interfaces)
perl from cpan.org (only for build process and only if you want to generate code from .sg)
plaindoc from http://mercnet.pt/plaindoc/pd.html (only for build process, for code generation from .sg, and for documentation)
Although technically not needed to build zxid, you will need an IdP to test against. We do not, at the time, supply one, so you will need to find a third party, perhaps a free download of one of the commercial ones like
Lasso: http://lasso.entrouvert.org/
While zxid will run easily under Apache httpd (see recipe), for sake of simplicity we first illustrate running it with mini_httpd(8), a very simple SSL capable web server by Jef Poskanzer.
You can download the source for mini_httpd from http://www.acme.com/software/mini_httpd/
You should already have installed OpenSSL, or quite probably OpenSSL shipped with your distribution. If it is not located at /usr/local/ssl, the you need to edit the mini_httpd Makefile to indicate where it is. At any rate you need to uncomment all lines that start by SSL_ in the Makefile. Then say
make
Now copy the mini_httpd binary somewhere in your path.
After building zxid, cd to zxid directory and run
mini_httpd -p 8443 -c 'zxid*' -S -E zxid.pem
where
-p 8443 specifies the port to listen to -c 'zxid*' specifies that URL paths with "zxid" are CGI scripts -S specifies that https is to be used -E zxid.pem specifies the SSL certificate to use
See Apache recipe for alternative that avoids mini_httpd, but is more complicated otherwise.
N.B. The zxid.pem certificate and private key combo is shipped with zxid for demonstration purposes. Obviously everybody who downloads zxid has that private key, so there is no real security what-so-ever. For production use, you must generate, or acquire, your own private key-certificate pair (and keep the private key secret). See Certificates chapter for further info.
Edit your /etc/hosts file so that the definition of localhost also includes sp1.zxidcommon.org and sp1.zxidsp.org domain names, e.g:
127.0.0.1 localhost sp1.zxidcommon.org sp1.zxidsp.org
Point your browser to
https://sp1.zxidsp.org:8443/zxid
or if you do not want the common domain cookie check
https://sp1.zxidsp.org:8443/zxid?o=E
Dynamic linking problems
If accessing the URL (while running mini_httpd) you get no error message and no content - everything just mysteriously fails - you may be hitting a dynamic linking problem. If mini_httpd(8) fails to launch CGI script it will silently fail. This is unfortunate, but I guess that is what the "mini" in the name implies.
To make matters even worse, mini_httpd(8), probably in the interest of security, will ignore LD_LIBRARY_PATH variable. Apparently it has its fixed notion of the library paths that is set at compile time.
If you suspect this problem, try following:
Create shell script called test.sh:
#!/bin/sh
echo Content-Type: text/plain
echo
echo Test $$
echo lib_path is --$LD_LIBRARY_PATH--
ldd zxid
./zxid -h 2>&1
echo Exit value --$?--
Restart mini_httpd(8) like this
chmod a+x test.sh
mini_httpd -p 8443 -c test.sh -S -E zxid.pem -l mini.out
Access https://sp1.zxidsp.org:8443/test.sh - you may see something like
Test 1655
lib_path is --/usr/local/lib:/usr/lib--
./zxid: error while loading shared libraries: libcurl.so.3: cannot
open shared object file: No such file or directory
Now you at least see why it's failing (in this case the directory where libcurl was installed is not in mini_httpd's notion of LD_LIBRARY_PATH). If the zxid binary runs fine from comman line, try `ldd zxid' to see where it is finding its libraries.
Easiest dirty fix is to copy the missing libraries to one of the hardwired directories of mini_httpd(8) (e.g. /usr/lib). More sophisticated fixes include using ldconfig(8), recompiling your mini_httpd(8), or statically linking the offending library into zxid binary.
Currently zxid does not ship with an IdP (though the necessary protocol encoders and decoders are latently available in libzxid, should anyone wish to make an attempt to hack an IdP together). For you to test zxid, you will need to acquire an IdP from somewhere - any vendor whose product is SAML 2.0 certified will do. Possible sources are
http://symlabs.com/Products/SFIAM.html who have a free download of commercial product
Lasso: http://lasso.entrouvert.org/
If you do not want to install an IdP yourself (even for testing), find someone who already runs one and ask if they would be willing to load the metadata of your zxid SP. If you do this, you will need to get externally visible domain names. This canned tutorial uses /etc/hosts (see previous step) which is only visible on your own machine.
Once you get your IdP up and running, you need to make sure it accepts
the zxid SP in its Circle of Trust (CoT). This is done by placing
the metadata of the SP in right place in the IdP product configuration.
If your IdP supports automatic CoT management, just turn it on
and chances are you are done.
If not, you can obtain the zxid SP metadata (which is slightly different for each install so you can't just copy it from existing install) from
https://sp1.zxidsp.org:8443/zxid?o=B
This URL is the well known location method metadata URL. It is also the SP Entity ID or Provider ID, should the IdP product ask for this in its configuration. If the IdP product needs you to supply the metadata manually as an xml file, just point your web browser to the above URL and save to file, or use curl(1) or wget(1).
zxid SP, by default, has automatic fetching of IdP metadata enabled so there is no manual configuration step needed, provided that the IdP supports the well known location method. All SAML 2.0 certified IdP implementations must support it (but you may still need to enable it in configuration). See [SAML2meta] section 4.1 "Publication and Resolution via Well-Known Location", p.29, for normative description of this method.
However, you will need the Entity ID (Provider ID) of the IdP. This is the URL that the IdP uses for well known location method of metadata sharing. You may need to dig the IdP documentation or GUI for a while to find it. If you already have the IdP metadata as an xml file, open it and look for EntityDescriptor/entityID. If you already have the file, you can also import it manually by running the following command
./zxid -import file:///path/to/idp-meta.xml
But the preferred method still is: just let the automatic method do its job.
Start at
https://sp1.zxidsp.org:8443/zxid
or
https://sp1.zxidsp.org:8443/zxid?o=E
If you had common domain cookie already in place, and you are already logged in the IdP, the SSO may happen automatically (go to step 3). The automatic experience will be typical when you use SSO regularly for more than one web site (i.e. several SPs).
However, if you get a screen titled "ZXID SP SSO", you need to paste the IdP's Entity ID to the supplied field and click "Login". If zxid SP already obtained the metadata for the IdP, you may also see a button specific for your IdP (and in this case there is no need to know the Entity ID anymore or paste anything).
Next step depends on the IdP product you are using. Usually a login screen will appear asking for user name and password. Supply these and login. You will need an account at the IdP.
For more slick IdPs, that's all you need to do and you will land right back at the zxid SP page titled "ZXID SP Management".
Congratulations, you have made your first SSO!
However, some IdPs will pester you with additional questions and you will have to jump through their hoops. A typical question is whether you want to accept a federation. You do.
Sometimes the federation question does not appear automatically
and you need to figure out a way to create a federation
in their user interface and how to get them to send you
back to the SP. Sometimes the word used is "account linking"
instead of federation.
ZXID ships with working demo configuration so you can run it right away and once you are familiar with the concepts, you can return to this chapter.
ZXID uses a configuration file in default path
/var/zxid/zxid.conf
for figuring out its parameters. If this file is not present, built-in
default configuration is used (see zxidconf.h).
The built-in configuration will allow you to test
features of ZXID, but should not be used in production because it uses
default certificates and private keys. Obviously the demo private key
is of public knowledge since it is distributed with the ZXID package,
and as such it provides no privacy protection what-so-ever. For
production use you MUST generate your own certificate and private key.
Usually configuring a system involves following tasks
Configure web server (see your web server documentation)
HTTPS operation and TLS certificate. In the minimum you need the main site, but you may want to configure the Common Domain Cookie virtual host as well.
Arrange for ZXID to be invoked. This could mean configuring zxid, zxid-java.sh, or zxid.pl to be recognized as a CGI script, or it could mean setting up your mod_perl or mod_php system to call ZXID at the appropriate place.
Configure ZXID, including signing certificate and CoT with peer metadata
generate or acquire certificate
Obtain peer metadata (from their well known location) or enable Auto CoT feature.
Configure CoT peers with your metadata. They can download your metadata from your well known location (which is the URL that is your entity ID). For this to happen you need to have web server and ZXID up and running.
The root directory of ZXID configuration files and directories. By default this is /var/zxid and has following directories and files in it
/var/zxid/ | +-- zxid.conf Main configuration file +-- pem/ Our certificates +-- cot/ Metadata of CoT partners (metadata cache) +-- ses/ Sessions `-- log/ Log files, pid files, and the like
Directory that holds various certificates. The certificates have hardwired names that are not configurable.
Certification Authority certificates. These are used for validating any certificates received from peers (other sites on the CoT). The CA certificates may also be shipped to the peers to facilitate them validating our signatures. This is especially relevant if the certificate is issued by multilayer CA hierarchy where the peer may not have the intermediate CA certificates.
The signing certificate AND private key (concatenated in one file). The private key MUST NOT be encrypted (there will not be any opportunity to supply decryption password).
The encryption certificate AND private key (concatenated in one file). The private key MUST NOT be encrypted (there will not be any opportunity to supply decryption password). The signing certificate can be used as the encryption certificate. If encryption certificate is not specified it will default to signing certificate.
In addition to the above certificates and private keys, you will need to configure your web server to use TLS or SSL certificates for the main site and the Common Domain site. We suggest the following naming
SSL or TLS certificate for main site. In order to avoid browser warnings, the CN field of this certificate should match the domain name of the site. The SSL certificate can be same as signing or encryption certificate.
SSL or TLS certificate for Common Domain Cookie introduction site. In order to avoid browser warnings, the CN field of this certificate should match the domain name of the site. The SSL certificate can be same as signing or encryption certificate.
Directory that holds metadata of the Circle of Trust (CoT) partners. If Auto CoT is enabled, this directory needs to be writable at run time.
Typical metadata file path would be
/var/zxid/cot/Inkl5fOnhVNa0LbWjHem2Y2UphY
If the metadata file appears in this directory, then the entity is in the CoT.
The file name component of the path is safe base64 encoded SHA1 hash of the Entity ID, with last character stripped (that character would always be an equals sign).
During zxid project development phase (ongoing as of Jan 2007), most configuration related documentation will be kept as comments in zxidconf.h, which you should see.
Configuration file is line oriented. Comments can be introduced with cardinal (#) and empty lines are ignored. End of line comments are NOT supported at this time.
Each configuration option is a name=value pair. The name is the same as in zxidconf.h except that ZXID_ prefix does not appear. Only single line values are supported, but you can embed characters using URI encoding, e.g. %0a for newline. In fact, the configuration lines are treated as CGI variables, thus & can also be used as separator instead of newline (and needs to be encoded if not intended as separator).
When option is not specified, the default from zxidconf.h prevails. Thus in the following the PATH specification is redundant.
To give some idea consider following /var/zxid/zxid.conf example:
# Demo /var/zxid/zxid.conf file PATH=/var/zxid URL=https://sp.mydomain.com:8443/zxid NICE_NAME=My SP's human%0areadable name. #EOF
N.B. zxidconf.h contains a wealth of logging related config options.
Tip: Your web server also has logging options. You may want to correlate the web server logs with zxid audit logs.
In serious use of SSO it is fundamental that the relying party, the SP, WSC, or WSP, archives the digitally signed evidence that justifies its actions. Generally this means that at least the SSO or credential assertions have to be archived. Quite often, especially in the WSC world, the entire SOAP response (which may be partially signed) needs to be preserved as a proof of an authorized action or attested attributes.
To lesser extent, it is also important that the issuing party, the IdP (or sometimes the DS, PS, WSC, or WSP), keeps records so that it can confirm or refute the claims of the relying party -- in the minimum it should be able to refute any obviously false claim and it should be able to detect breaches of its own security arrangements, e.g. situations where somebody is signing messages in its name although internal audit trail demonstrates this to be impossible. The IdP audit trail consists of preserving any (signed) request made by anyone as well as preserving every (signed) response it makes.
Generally every assertion, request, and response will have its unique
ID that can be used as the primary key, or filename, for storing it in
a database. Unfortunately these namespaces
are not disjoint
(it is not very well specified in any of the standards how they
interact or how wide their uniqueness properties are).
The only safe assumption is the pessimistic one: each
type of object observes a unique namespace only towards its issuer and
type and hence we need to map such namespaces to subdirectories.
Please consider following layout of the log directory:
/var/zxid/
|
+-- zxid.conf Main configuration file
+-- pem/ Our certificates
+-- cot/ Metadata of CoT partners (metadata cache)
+-- ses/ Sessions
`-- log/ Log files, pid files, and the like
|
+-- issue/
| |
| +-- SHA1NAME/ Evidence given to an entity ID is kept in this directory
| | |
| | +-- a7n/ Assertions issued to the given 3rd party, named by AssertionID
| | `-- msg/ Messages of any type issued to the given 3rd party, named by MessageID
| ...
| `-- SHA1NAME2/ Evidence relating to another entity ID
|
+-- rely/
| |
| +-- SHA1NAME/ Evidence relating to given entity ID is kept in this directory
| | |
| | +-- a7n/ Assertions from 3rd parties, named by AssertionID
| | `-- msg/ Messages of any type from 3rd parties, named by MessageID
| ...
| `-- SHA1NAME2/ Evidence relating to another entity ID
|
+-- tmp/ Subdirectory used for atomic operations à la Maildir
+-- act Global activity log
+-- err Global error log
`-- debug Global debugging log
The log file is line oriented, one record per line irrespective of line length, and plain text: binary data is generally omitted or represented as (safe) base64. Fields are separated by exactly one space character (0x20), except for the last free format field. Records are separated by exactly one new line (0x0a) character (never by CRLF sequence).
The log file format supports
Plain text logging
Signed plain text logging using either RSA-SHA1 or DSA-SHA1
Symmetrically encrypted logging using either 3DES or AES
Asymmetrically encrypted logging using RSA (or DSA?)
Signed and symmetrically encrypted logging
Signed and Asymmetrically encrypted logging
All activity and error log file lines have the following format (any one of the 3):
# comment SE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC SE SIG OURTS SRCTS IP:PORT SUCCEID MID A7NID NID VVV RES OP PPP FMT
where
Log signing and encryption designator. In all cases the actual signing or encryption key is not identified on the log line. This will need to be determined out-of-band.
PlainPlain: not signed and not encrypted
RSA-SHA1 signed (x = any encryption)
DSA-SHA1 signed
SHA1 check-summed, but not signed (SSSS is the checksum)
Asymmetrically AES encrypted (x = any signing method)
Asymmetrically 3DES encrypted
Symmetrically AES encrypted (theoretical: how to safeguard the key?)
Symmetrically 3DES encrypted (theoretical: how to safeguard the key?)
Experimental arrangements.
Safe base64 encoded log encryption blob. In case of encryption blob, the rest of the log fields will not appear. Decrypted logline will contain fields starting from SSSS.
Safe base64 encoded log line signature blob. If no signature, this is a dash ("-").
Our time stamp, format YYYYMMDD-HHMMSS.TTT where TTT are the milliseconds. The time is always in GMT (UTC, Zulutime).
Source time stamp, format YYYYMMDD-HHMMSS.TTT. If TTT was not originally specified it is represented as "501". The time is always in GMT (UTC, Zulutime).
The IP address and the port number of the other end point (usually client, but could be spoofed, caveat emptor).
The SHA1 name of the entity (succinct entity ID without the equals sign).
Message ID relating to the log line. Allows message to be fetched from the database or the file system. Any relates-to or similar ID is only available by fetching the original message. Dash ("-") if none.
Assertion ID relating to the log line. Allows assertion to be fetched from the database or the file system. If message benefits from multiple assertions, this is the one relating to the outermost one. Other A7NIDs are only available by fetching the original assertion. Dash ("-") if none. If the assertion is encrypted and can not be decrypted, then placehoder "-enca7n-" is used.
IdP assigned NameID relating to the message, if any. If the NameID is encrypted and can not be decrypted, then placeholder "-encnid-" is used.
Signature validation codes
Capital Oh (not zero). All relevant signatures validate (generally assertion)
Unsupported or bad signature or message digest algorithm
Checksum of XML DSIG does not validate
The RSA layer of the signature does not validate
No signature detected.
Issuer metadata not found (or not in CoT, or corrupt metadata).
Assertion validity error (e.g. not in time range or wrong audience)
Operation failed or faulted by error code (low level protocol ok)
Extended signature validation code (generally failure)
Experimental signature validation code (generally failure)
Result of the operation.
Operation was success
Operation failed because client did not provide valid input
Operation failed due to server side error
Operation failed due to policy or permissions issue
Temporary error, client was encouraged to retry
Metadata related error (no metadata or parse error in metadata)
Redirect or recredential. Client was encouraged to retry.
Way point message. Neither success nor failure.
Extended result (generally failure)
Experimental result (generally failure)
The documented operation
Federation and SSO request succeeded, new federation was created.
SSO using federated ID was performed
SSO using temporary NameID was performed
Single Logout was completed
Defederation was performed
Server configuration (/var/zxid/zxid.conf) is bad
No metadata found after options exhausted (cache, fetch from net)
Metadata parsing error
XML parsing error in protocol
SAML call failed (often SOAP call)
Other error
For WSP the OP is the command verb that was exercised.
For WSC the OP is the command verb preceded by capital C, e.g. "CQuery".
Additional OP verbs may need to be specified for protocol substeps like artifact resolution (ART) and direct authentication (AUTH).
Artifact resolution request sent with SOAP (1)
Redirection with Authentication Request
Local Logout (1)
Redirection with Single Logout Request
Redirection with Manage NameID Request for changing NameID
Redirection with Manage NameID Request for defederation
Single Logout Request SOAP call made
Manage NameID Request for changing NameID SOAP call
Manage NameID Request for defederation SOAP call
SAML call OK (often SOAP call)
Additional OP verbs may need to be specified for other logging operations like regular web access logs (HEAD, GET, POST).
IdP Selection screen is shown (2)
Management screen is shown (2)
Logged in (by SSO or session). Show protected content. arg is sid. (1)
SP Command Dispatch (received POST or redir) (2)
My metadata was served to requester on the net (1)
Getting metadata from net (2)
Got metadata from net (1)
Unknown CGI options (0, but not implemented yet)
Operation dependent one most relevant parameter. Dash ("-") if none.
Operation dependent free-form data. May contain spaces. Dash ("-") if none.
Logs are enabled in the config file zxidconf.h (compile time) by ZXLOG macros which provide default values for the log flags in struct zxid_conf. Each log flag is a bitmask of signing and encryption options. Zero value means no logging. "1" can be used to enable plain text logging.
Log signing may help you to argue that log evidence was (not) tampered with. You can configure the signing level in the config file zxidconf.h (compile time):
no signing (Px)
sha1 MD only (Sx)
RSA-SHA1 (Rx)
DSA-SHA1 (Dx)
For actual signing (options 2 and 3), the private key for signing must be available in /var/zxid/pem/logsign-nopw-cert.pem. Note that this file need not contain the actual certificate (but it may, it just will not be used).
The weak point of log signing is that if the private key is stolen, then someone can create falsified logs and the private key needs to be available on the point where the logs are generated - thus it is actually quite vulnerable.
Log encryption may help to keep the logs confidential. You can configure the configuration level in the config file zxidconf.h (compile time):
no encryption (xP)
RSA-AES (xA)
RSA-3DES (xT)
Symmetric AES (xB)
Symmetric 3DES (xU)
For RSA modes the public key for encryption must be available in /var/zxid/pem/logenc-nopw-cert.pem. Note that the private key should NOT be kept in this file: the whole point of public key encryption is that even if your server machine is stolen, the bad guys can't access the logs - if the private key was anywhere in the stolen machine, they will find it.
For symmetric encryption the key is the SHA1 hash of file /var/zxid/pem/logenc.key. Obviously this key must be kept secret, but see the caveat about stolen machine in the previous paragraph.
All encryption modes, except for 0, [RFC1951] zip compress the log line before encryption and safe-base64 encode the result of the encryption. All encryption modes, except 0 and 1, prefix the zipped log line with 128 bit nonce before encrypting.
The algorithm is roughly
If encrypt, zip the raw log line
If sign, compute the signature (over zipped version if applicable)
Prepend signature blob to log line. If encrypting, the signature is embedded in binary form, otherwise it is embedded in safe-base64 form.
If encrypt, perform the encryption.
If encrypt, apply safe-base64.
The supplied tool zxlogview(1) allows the logs to be decrypted and the signatures verified.
./zxlogview logsign-nopw-cert.pem logenc-nopw-cert.pem <some-log-lines
Note that for zxlogview(1) to work the logsign-nopw-cert.pem needs to contain the public key (and need not contain the privatekey) which is the opposite of the situation what zxid(1) needs to see in order to sign. Similarly logenc-nopw-cert.pem needs to contain the private key (and may contain the certificate, though this will not be used).
N.B. While encrypted logs are cool, you should evaluate the gain against the incovenience: if you encrypt them, the lesser mortal sysadmins may not be able to debug your installation because they do not know how to decrypt logs or you are not willing to trust them with the keys. For this reason, you can configure the encryption of error log separately.
For [RFC1951] zipped safe-base64 [RFC3548] output the input to base64 encoding is
LLSSSSZZZZZZZZZZZZZZ -- RFC1951 zipped safe-base64
For encrypted modes the input to AES (or other symmetric cipher) is
NNNNLLSSSSZZZZZZZZZZ -- Note how nonce is prepended
The NNNN is used as initialization vector and actual encryption encompasses LL, SSSS, and ZZZZ.
In RSA-AES the session key is encrypted using RSA and prepended to the input for base64 encoding.
KKEEEECCCCCCCCCCCCCC -- RSA-AES: note prepended session key
16 bytes of nonce. This is used as initialization vector
for AES or 3DES cipher operated in CBC mode.
Bigendian integer representing signature length in bytes.
0 means none. Negative values reserved for future use.
The signature in binary
Bigendian integer representing encrypted session key
length in bytes. Negative values are reserved for future use.
RSA encrypted session key in binary
Ciphertext from the symmetric cipher, including nonce.
In RSA operations RSA_PKCS1_OAEP_PADDING padding is used (PKCS #1 v2.0).
Logging of assertions is controlled by configuration options ZXLOG_ISSUE_A7N and ZXLOG_RELY_A7N. At least ZXLOG_RELY_A7N should be turned on for ID-WSF web services to work correctly. Logging relied assertions also allows detection of duplicate assertion IDs. Logging, or not, of issued assertions does not have any operational effect and is only for audit trail purposes.
Assertions are logged in directories depending on issuer's sha1 name.
/var/zxid/log/rely/ISSUER-SHA1-NAME/a7n/A7N-ID-AS-SHA1
Sha1 names are used to avoid any attack through issuer entity ID or the assertion ID being evilly crafted to contain shell metacharacters or filesystem significant characters.
Assertions issued by ourselves follow similar pattern
/var/zxid/log/issue/DEST-SHA1-NAME/a7n/A7N-ID-AS-SHA1
If the logfile starts by less-than character ("<") then it is in plain text. Encrypted or signed formats will start in another way, but are not specified at this time.
N.B. The relied-on assertions may be referenced from session objects and used in construction of credentials for ID-WSF based web services calls. Therefore the rely directory should not be cleaned too aggressively: the assertions must remain there until the referencing session expires.
Logging of requests and responses is controlled by ZXLOG_ISSUE_MSG and ZXLOG_RELY_MSG. Logging, or not, messages has no operational effect and is only for audit trail purposes. If logging of relied messages is turned on, then it is possible to detect duplicate message IDs.
Request messages are logged in directories depending on issuer's sha1 name.
/var/zxid/log/rely/ISSUER-SHA1-NAME/msg/REQ-ID-AS-SHA1
Sha1 names are used to avoid any attack through issuer entity ID or the assertion ID being evilly crafted to contain shell metacharacters or filesystem significant characters.
Responses issued by ourselves follow similar pattern
/var/zxid/log/issue/DEST-SHA1-NAME/msg/RESP-ID-AS-SHA1
If the logfile starts by less-than character ("<") then it is in plain text. Encrypted or signed formats will start in another way, but are not specified at this time.
The ZXID session system serves three purposes:
Remember whether user has logged in. The session ID is carried either in a cookie or as part of the URL.
Make it possible to perform Single Logout (SLO) and certain federation management tasks.
Remember the service end points (EPRs) that were either
supplied as bootstrap attributes in the SSO assertion, or
later discovered
The biggest complication is the requirement to remember the EPRs and the solution currently used is to keep them as files in a per session directory under the /var/zxid/ses tree.
/var/zxid/ | +-- zxid.conf Main configuration file +-- pem/ Our certificates +-- cot/ Metadata of CoT partners (metadata cache) +-- ses/ Sessions | | | +-- SESID/ Each session has its own directory | | | +-- .ses The session file | +-- SVC,SHA1 Each bootstrap is kept in its own file | +-- user/ Local user accounts (if enabled) | | | +-- SHA1/ Each local user has a directory whose name is SHA1 | | of the user's NameID (idpnid) | +-- .mni Information needed by Name ID management | `-- log/ Log files, pid files, and the like
The session ID is an unguessable (but see ID_BITS configuration options) safe base64 encoded pseudorandom number. Unguessability ensures that the session can only be crated via SSO.
The service EPRs are XML documents whose name is composed from two components
SVC,SHA1
The service type URI, with file system unsafe characters (e.g. "/" and ",") folded to underscore ("_"). Purpose of the SVC is to allow quick identification, without opening, of the files that contain EPRs for a given service type. Only first 200 bytes of the service type are used.
safe base64 encoded SHA1 hash of the content of the EPR. The purpose of the SHA1 hash is to produce a unique identifier so that two distinct EPRs for same service will have different file names.
The session directory also contains .ses file. The first line is as follows (still subject to change, Oct 2007):
NameID|a7n-ref
The pipey symbol (|) is a field separator. Future versions may define further fields beyound these original two. All other lines are reserved for future expansion. Fields:
NameID, extracted during SSO
Filesystem path to the SSO assertion.
User directories are used for storage of local account information. Since many web applications, to which ZXID may be integrated, already have their own local user storage, the ZXID user directory is optional, see USER_LOCAL configuration option.
IdP initiated ManageNameID requests depend on local user accounts, so if you want this to work you need to enable them. Local user account management may be useful on its own right if your application does not yet have such system. If it has, you probably want to continue to use the application's own system.
Each user is represented by a file whose filename is safe base64 of the SHA1 hash of the user's NameID.
Inside the directory, a file called .mni captures the information needed for NameID Management. It is expected that other files about the user may be populated to capture other aspects. Your own applications could even create files here.
The first line of the .mni file is as follows
FMT|IDPEnt|SPqual|NameID|MNIptr
The pipey symbol (|) is a field separator. Future versions may define further fields beyound these original two. All other lines are reserved for future expansion. Fields:
NameID Format
IdP entity ID that qualifies the NameID (namespace if you like). This usually corresponds to the NameQualifier of
SP entity or affilitation ID (optionally) sent by IdP. This further qualifies the namespace of the Name ID.
NameID of the account
If NameID Management has been used to change the IdP assigned NameID, then the new NameID. There will be a local user account directory for the new NameID. Consider this as a sort of symlink functionality.
make cleaner make dep ENA_GEN=1 make make all ENA_GEN=1
The build process of ZXID relies heavily on code generation techniques that are not for the faint of heart. Some of these techniques, like xsd2sg.pl were innovated for this project, while others like SWIG and gperf are existing software. Here and there some additional perl(1) and sed(1) scripts are run to fix a thing or two.
Carefully study the Makefile, and this should all start to make sense. Please note that there is no configuration script and GNU Auto-tools (GNU Autohell) are not used. This is because they have been evaluated to be unsuitable to this project (or to author's tastes). If the Makefile does not do what you want, you should first study if you can change necessary variables using localconf.mk, or if that does not work, then just edit the Makefile itself. You can temporarily customize the variables in the Makefile by providing new value on command line, e.g.
make CC=cc # override the default of CC=gcc
libzxid contains thousands of functions and any given application is
unlikely to use them all. Thus the easiest, safest, no loss of
functionality, way to reduce the footprint is to simply enable
compiler and linker flags that support dead function
elimination.
On gcc you should investigate compilation with "-ffunction-sections -fdata-sections" and linking with "-Wl,--gc-sections".
If you need to squeeze zxid into as minimal space as possible, some functionality trade-offs are supported. I stress that you should only attempt these trade-offs once you are familiar with zxid and know what you are doing. The canned install instructions and tutorial walk thrus stop working if you omit significant functionality.
Comment out the -DUSE_OPENSSL flag from CFLAGS in Makefile and recompile.
This will cripple zxid from security perspective because it will no longer be able to verify or generate digital signatures. Unless your environment does not need trust and security, or you understand thoroughly how to provide trust and security by other means, it is a very bad idea to compile without OpenSSL.
N.B. Compiling, or not, zxid with OpenSSL does not affect whether your web server will use SSL or TLS. Unless you know what you are doing, you should be using SSL at web server layer. Given that SSL is used at web server layer, the memory footprint savings you would gain from compiling zxid without OpenSSL may be negligible if you use dynamic linking.
Comment out the -DUSE_CURL flag from CFLAGS in Makefile and recompile.
Disabling libcurl does not have adverse security implications: you only loose some functionality and depending on your situation you may well be able to live without it.
Without libcurl, zxid can not act as a SOAP client. This has a few consequences
Artifact profile for SSO is not supported because it needs SOAP to resolve the artifact. In most cases a perfectly viable alternative is to use POST profile for SSO.
SOAP profiles for Single Logout and NameID management (aka defederation) are not supported. You can use the redirect profiles and get mostly the same functionality.
Automatic CoT metadata fetching using well known location method is not supported without libcurl. You can fetch the metadata manually, e.g. using web browser, and place it in /var/zxid/cot directory.
If you want to manually control your Circle of Trust
relationships, you probably want to do this anyway so
loss of automatic functionality may be a non-issue.
Web Services Client (WSC) functionality is not supported without libcurl. Effectively this is just another case of "SOAP needed". If you have your own SOAP implementation, you may, at lesser automation, achieve much of the same functionality by calling the encoder and decoder functions manually.
zlib is used mainly in redirect profiles. Since zlib is widely avvailable and its foot print is small, we have made no supported provision to compile without it. If you hack something together, let us know.
WARNING: Only regularly tested configuration is to compile all standards in.
On space constrained systems you may shed additional weight by only compiling in the IdM standards you actually use. Of course, if you do not use them, the dead function elimination should take care of them, but sometimes you can gain additional savings in space and especially compile time.
Another reason could be, in the land of the free, if some modules
are covered by a software patent, you may want to compile a binary
without the contested functionality.
You can tweak the flags, shown in accompanying table, in the Makefile or by supplying new values in localconf.mk or on commend line. For example
make TARGET=sol8 ENA_SAML2=0
would disable SAML 2.0 (and trigger build for Sparc Solaris 8).
Table 1:Conditional inclusion of standards
| Makefile flag | Standard | Comments |
|---|---|---|
| ENA_SSO=1 | All SSO | Must be enabled for any of SSO to work |
| ENA_SAML2=1 | SAML 2.0 | |
| ENA_FF12=1 | ID-FF 1.2 | Requires ENA_SAML11=1 |
| ENA_SAML11=1 | SAML 1.1 | |
| ENA_WSF=1 | All WSF | Must be enabled for any of WSF to work |
| ENA_WSF2=1 | ID-WSF 2.0 | |
| ENA_WSF11=1 | ID-WSF 1.1 |
You can use localconf.mk to remember your own make options, such as TARGET and different ENA flags, without editing the distributed Makefile.
One useful option to put in localconf.mk is ENA_GEN which will turn on the dependencies that will trigger generation of the files in zxid/c directory. For example
echo 'ENA_GEN=1' >>localconf.mk make
WARNING: If you are confused about compilation flags appearing "out of nowhere", despite not being mentioned in the Makefile, be sure you have not inadvertently created a localconf.mk (perhaps you rsynced the sources from another machine and forgot to remove localconf.mk). A similar problem can occur if you accidentally copied deps.dep from another machine. It will reference the dependencies with the paths of that machine. Just remove the deps.dep to solve this issue.
ZXID was mostly developed on gcc 3.4.6 and explicitly has not been tested on 4.x series of gcc (due to deprecation of commonly useful features in that gcc series). If you hit compile time problems with 4.x gcc, try with 3.4.x series gcc first, before reporting bugs.
***
There are some, yet unspecified, compilation or linking errors that manifest on 64 bit or mixed 32 and 64 bit Linux platforms. Current suggested workaround is to compile 32 bit only.
Linking error that has been reported a lot on the Google for other software packages:
/usr/lib/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x2a): undefined reference to `__init_array_start'
/usr/bin/ld: zxidjava/libzxidjni.so: hidden symbol `__fini_array_end' isn't defined
/usr/bin/ld: final link failed: Nonrepresentable section on output
This seems to be either glibc version related or linker configuration related (or compiler version?). See
http://www-gatago.com/gnu/gcc/help/43379636.html
http://lists.debian.org/debian-68k/2006/07/msg00017.html
The verdict seems to be that somewhere in glibc-2.3 development it was broken by design and nobody cared to provide any viable fix short of upgrading your binutils. Seems to be Ulrich Drepper at it again, turning symbols hidden in teeny version number upgrade.
A symptom of this is if this command gives the follwing output
ld --verbose | egrep '__init_array_(start|end)'
PROVIDE_HIDDEN (__init_array_start = .);
PROVIDE_HIDDEN (__init_array_end = .);
You can manually attempt to link with
gcc -nostdlib -o zxidjava/libzxidjni.so -shared --export-all-symbols -Wl,-whole-archive -Wl,--allow-multiple-definition zxidjava/zxid_wrap.o -L. -lzxid -lpthread -L/usr/local/lib -L/usr/local/ssl/lib -lcrypto -lcurl -lz
The trick is to supply the -nostdlib flag.
ZXID project considers this to be glibc or binutils bug and will not investigate further. Either use the workaround link line or upgrade binutils, glibc, or both and complain to glibc authors or binutils authors.
The xsd2sg.pl tool, distributed as part of Plaindoc (http://mercnet.pt/plaindoc/pd.html) system, is at the heart of the ZXID code generation. Unfortunately the tool is still in flux. What follows is general outline valid as of March 2007.
xsd2sg.pl can be invoked in three ways (see xsd2sg.pl --help), but the invocation of interest to use is the -S SG to XSD with Code generation mode. This mode takes as inputs all .sg files and names of decoding root elelment. It will generate one mega parser that is capable of decoding any root element (and since root elements contain other elements, then really all elements). The decoder works by recursive descent parser principle so there will be smaller decoder functions to call. Similarily the encoder is generated by creating many unit encoders for different elements. Then the parent elements will call the child element encoders.
xsd2sg.pl first processes the .sg files to XSD. As a side effect it populates %dt multidimentsional hash
$dt{'element'}{elemname}[array-of-sublemens-and-attrs]
$dt{'attribute'}{attrname} = "";
$dt{'complexType'}{typename}[array-of-sublemens-and-attrs]
$dt{'group'}{groupname}[array-of-sublemens-and-attrs]
$dt{'attributeGroup'}{agname}[array-of-attrs]
Where the array-of-subelems-and-attrs can contain tag or reference to fundamental or derived type, e.g.
"tag$sa:Assertion$min$max" "ref$xs:anyURI$" "ref$sa:Assertion$" "base$$0$1$base-type" "enum$n1$n2$n3$n4$n5" "any$$min$max$pc$ns" "anyAttribute$$min$1" "_d$$0$1$simplecontent"
Since the concrete goal is to generate data structures for elements irrespective of how types were used to describe the data, we need to expand any type reference into element definition where it appears. This is done by expand_element() which will in its turn call expand_complex_type(), expand_group() and expand_attribute_group() to do the job.
Once %dt is in expanded form, the get_element() is called for each XML namespace. It will generate the code for encoders and decoders for the elements in the XML namespace. Finally the root decoder is gnerated using gen_element(). Furing generation following template files are used
aux-templ.c - Code generation template for auxiliary functions dec-templ.c - Code generation template for decoders enc-templ.c - Code generation template for encoders getput-templ.c - Code generation template for accessor functions
A lot of the generated headers are simply hard coded in the xsd2sg.pl (i.e. no templates).
perl CGI example: zxid.pl
using with mod_perl
After building the main zxid tree, you can
cd Net perl Makefile.PL make make test # Tests are extremely sparse at the moment make install
This assumes you use the pregenerated Net/SAML_wrap.c and Net/SAML.pm files that we distribute. If you wish to generate these files from origin, you need to have SWIG installed and then say in main zxid directory
make perlmod ENA_GEN=1 # Makes all available perl modules (including heavy low level ones) make samlmod ENA_GEN=1 # Only makes Net::SAML (much faster) make wsfmod ENA_GEN=1 # Only makes Net::WSF (much faster)
WARNING: Low level interface is baroque, and consequently, it will take a lot of disk space, RAM and CPU to build it: 100 MB would not be exaggeration and over an hour (on 1GHz CPU). Build time memory consumption of single cc1 process will be over 256 MB of RAM. You have been warned.
Net::SAML - The high level interfaces for Single Sign-On (SSO)
Net::SAML::Raw - Low level assertion and protocol manipulation interfaces
Net::SAML::Metadata - Low level metadata manipulation interfaces
Net::WSF - The high level interfaces for Web Services Frameworks (WSF)
Net::WSF::Raw - The low level interfaces for WSF variants
Net::WSF::WSC - The high level interfaces for Web Services Clients
Net::WSF::WSC:Raw
The perl APIs were generated from the C .h files using SWIG. Generally any C functions and constants that start by zxid_, ZXID_, SAML2_, or SAML_ have that prefix changed to Net::SAML::. Note, however, that the zx_ prefix is not stripped.
Since ZXID wants to keep strings in many places in length + data representation, namely as struct zx_str, SWIG typemaps were used to make this happen automatically. Thus any C function that takes as an argument struct zx_str* can take a perl string directly. Similarly any C function that returns such a pointer, will return a perl string instead. As a final goodie, any C function, such as
struct zx_str* zx_ref_len_str(struct zx_ctx* c, int len, char* s);
that takes length and s as explicit arguments, takes only single argument that is a perl string (the one argument automatically satisfies two C arguments, thanks to a type map). The above could be called like
$a = Net::SAML::zx_ref_len_str(c, "foo");
First the "foo" satisfies both len and ~s~, and then the return value is converted back to perl string.
To test the perl module, you must restart the mini_httpd(8) so that it recognizes zxid.pl as CGI script:
mini_httpd -p 8443 -c zxid.pl -S -E zxid.pem
Then start browsing from
https://sp1.zxidsp.org:8443/zxid.pl
or if you want to avoid the common domain cookie check
https://sp1.zxidsp.org:8443/zxid.pl?o=E
You can run zxid.pl under mod_perl using the Apache::Registry module. See Apache recipe for how to compile Apache to support mod_perl. After configuration it should work the same as the CGI approach.
As bizarre as it may sound, it is actually quite feasible to debug libzxid and the SAML_wrap.c using GDB while in perl. For example
cd zxid gdb /usr/local/bin/perl set env QUERY_STRING=o=E r ./zxid.pl
If the script crashes inside the C code, GDB will perfectly reasonably take control, allowing you to see stack back-trace (bt) and examine variables. Of course it helps if openssl and perl were compiled with debug symbols (libzxid is compiled with debug symbols by default), but even if they weren't you can usually at least get some clue.
When preparing a perl module, generally Makefile.PL mechanism causes the same compilation flags to be used as were used to compile the perl itself. Generally this is good, but if libzxid was compiled with different flags, mysterious errors can crop up. For example, I compile my libzxid against openssl that I have also compiled myself. However, I once had a bug where the perl had been compiled such that the Linux distribution's incompatible openssl would be picked by perl compile flags, resulting in mystery crashes deep inside openssl ASN.1 decoder routines (c2i_ASN1_INTEGER() while in d2i_X509() to be exact). When I issued `info files' in GDB I finally realized that I was using the wrong openssl library.
The PHP integration is incomplete due to incomplete support in SWIG for php5. However, enough interface exists to get most high level API working and thus successfully run an SP.
After building main zxid distribution, say
make phpzxid
You MUST have php-config(1) in path. If not, try
make phpzxid PHP_CONFIG=/path/to/php-config
If the extension built successfully, you can use it by copying it to a suitable place, e.g.
make phpzxid_install
The install again uses the php-config(1) to figure out where php(1) can find the module.
Next you need to decide whether to run under Apache mod_php setup (apache), or as CGI (any web server).
See Apache recipe for how to compile Apache to support mod_php.
In the CGI case you generally make sure your CGI script starts like
#!/usr/bin/php
<?
dl("php_zxid.so"); # These three lines can go to initialization: they only need to run once
$conf = "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxidhlo.php";
$cf = zxid_new_conf_to_cf($conf);
?>
The first line makes sure the file is executed with php interpreter. You should change it to match the path where your php is installed. You also need to make your CGI script executable, e.g:
chmod a+x mycgi.php
Then you place the CGI script in a directory in the document tree of the web site and make sure your http server is configured (permitted) to execute CGI scripts in that directory.
One tricky thing that can go wrong is dynamic linking. When you compiled the php_zxid.so module, some linking dependencies are usually created. Problem arises if some of the dependencies are not in the paths allowed for dynamic linking by your web server. The paths allowed by web server can easily be different than in your shell and some web servers even ignore LD_LIBRARY_PATH environment variable. Sometimes you just have to copy the dependency libraries to one of the allowed directories. This is "dirty", but works. See ldconfig(8) and section ?ZXID-Installing-CannedTutorialRunningZXIDasCGIundermini_httpd-AccessingZXID? for further information.
You can easily see the dependencies using ldd(1)
ldd /apps/php/5.1.6/lib/php/extensions/no-debug-non-zts-20050922/php_zxid.so
linux-gate.so.1 => (0xffffe000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb7796000)
libdl.so.2 => /lib/libdl.so.2 (0xb7792000)
libcurl.so.3 => /apps/lib/libcurl.so.3 (0xb7611000)
libz.so.1 => /apps/lib/libz.so.1 (0xb75fe000)
libc.so.6 => /lib/libc.so.6 (0xb74dd000)
/lib/ld-linux.so.2 (0x80000000)
In this example the suspect library dependencies are /apps/lib/libcurl.so.3 and /apps/lib/libz.so.1 because they are outside normal places, i.e. /lib and /usr/lib.
Another thing to remember is that CGI specification requires that the Content-Type header and an empty line (to separate headers from content) is emitted before the actual page. If this fails to happen, the page will mysteriously not appear although your script ran successfully.
Sometimes the debug output can end up in stdout (e.g. somewhere stderr was redirected to stdout) and this will garble the returned web page. Easy fix is to disable debug output by not supplying ZXID_AUTO_DEBUG. See section ?ZXID-ZXID_simpleAPI-HelloWorld-AUTOoptions?.
To use the ZXID PHP extension you must add near beginning of your script
dl("php_zxid.so"); // Load the module
You may need to tweak the paths, or LD_LIBRARY_PATH, to get this to work.
After this, you can use the PHP interface much the same way as you would use the C interface. See the distributed zxid.php and zxidhlo.php for further usage examples.
** TBD using SWIG. Very preliminary support in Makefile exists, but ** this has not been tested in any real world set up.
THe Python extension is built into subdirectory py with command
make pyzxid
The result should be py/py_zxid.so
After building main zxid distribution, say
make javazxid
You must have set JNI_INC variable correctly in the Makefile (or in localconf.mk) and javac must be in path (or you must set JAVAC variable). For the servlet or Tomcat support, you must make sure SERVLET_PATH points to your servlet-api.jar file. The ZXID Java interface has been mainly tested with j2sdk1.4.2 and some versions of Java SDK 1.5.
If you have done changes that require regeneration of the zxidjava/zxid_wrap.c file you should build with
make javazxid ENA_GEN=1
but this requires that you have swig(1) installed. Depending on the changes it may also require xsd2sg.pl and gperf(1), see "Compilation for Experts" section, above, for full explanation. As of January 2007, all of the Java JNI interface is swig(1) generated - there are no human authored files. However, we anticipate building a helper Java library to facilitate use of the JNI - contributions welcome.
After compilation, just copy the class files and the libzxidjni.so to suitable locations in your system (Makefile lacks any specific Java installation target because the author has not yet made up his mind about what makes sense). When you run Java programs that use the zxidjni class, you must makes sure the libzxidjni.so is found by the dynamic linker - usually this means setting LD_LIBRARY_PATH environment variable. The zxid-java.sh shell script demonstrates how to do this for the example CGI program zxid.java.
The resulting library is called libzxidjni.jnilib
You may need to supply additional arguments to java command:
java -classpath .:zxidjava -Djava.library.path=zxidjava zxid
On Mac, it seems export LD_LIBRARY_PATH=zxidjava is not needed.
For detailed usage examples of the Java interface you should study the zxid.java file.
The Java interface is contained in a package called zxidjava. This package contains the main wrapper class zxidjni as well as a number of data type specific classes. The zxidjni class is just a container for procedural zxid API - all methods of this class are static.
To start using the ZXID Java interface you need to do two things:
import zxidjava.*;
somewhere near top of your program pulls in the zxidjava package, including the zxidjni class. Then you need to have a static initializer smewhere in your program to pull in the libzxidjni.so:
public class myprog {
static {
System.loadLibrary("zxidjni");
}
public static void main(String argv[]) throws java.io.IOException
{
// ...
}
}
From here on you can call the C API procedures as static methods of the zxidjni class, e.g:
cf = zxidjni.new_conf("/var/zxid/");
Note that the zxid_ prefix is omitted in favour of the zxidjni class name qualifier.
The zx_str type is generally NOT nul terminated. We try to map these in the SWIG type maps, but any function returning char* currently maps to Java String type, yet there is no way of knowing how long the string type is. Therefore it's not safe to call functions returning char*. For example, consider
int zx_LEN_SO_sa_Action(struct zx_ctx* c, struct zx_sa_Action_s* x); char* zx_ENC_SO_sa_Action(struct zx_ctx* c, struct zx_sa_Action_s* x, char* p); struct zx_str* zx_EASY_ENC_SO_sa_Action(struct zx_ctx* c, struct zx_sa_Action_s* x);
The intent of the LEN_SO plus ENC_SO pair is that you first compute length, allocate sufficient buffer, and then render the encoding into the buffer. The ENC_SO in fact returns char* one past the end of the string. It is NOT safe to cal ENC_SO from Java because the SWIG generated interface would make Java believe that the char* one past end of string is a C string in its own right. Thus the only safe one to call is the EASY_ENC_SO variant.
ZXID distribution contains subdirectory called servlet. You should link this into webapps directory of Tomcat servlet container
cd ~/apache-tomcat-5.5.20/webapps ln -s ~/zxid-0.17/servlet zxidservlet
You also need to set allowLinking flag in apache-tomcat-5.5.20/conf/context.xml (the reloadable flag avoids having to restart Tomcat if you recompile the .class file):
<Context allowLinking="true" reloadable="true">...
The file servlet/WEB-INF/web.xml describes the example zxid application. The actual application lives in servlet/WEB-INF/classes which is actually just a symlink back to the top level of the ZXID distribution. Therefore the zxidhello.class file appears on the top level and the wrapper classes, which are scoped in zxidjava package, appear in zxidjava/ subdirectory. From the servlet container's perspective the directory appears to be apache-tomcat-5.5.20/webapps/zxidservlet/WEB-INF/classes/zxidjava
After make javazxid and restart of Tomcat (killall java; apache-tomcat-5.5.20/bin/startup.sh), you can access the application using URL (defined in servlet/WEB-INF/web.xml)
http://sp1.zxidsp.org:8080/zxidservlet/zxidHLO?o=E
If you get
java.lang.ClassNotFoundException: zxidhlo
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1355)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1201)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
java.lang.Thread.run(Thread.java:595)
Then you forgot to turn on the symlinks (see allowLinking, above).
If you get
java.lang.UnsatisfiedLinkError: no zxidjni in java.library.path
java.lang.ClassLoader.loadLibrary(ClassLoader.java:1517)
java.lang.Runtime.loadLibrary0(Runtime.java:788)
java.lang.System.loadLibrary(System.java:834)
zxidhlo.<clinit>(zxidhlo.java:20)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
java.lang.reflect.Constructor.newInstance(Constructor.java:274)
java.lang.Class.newInstance0(Class.java:308)
java.lang.Class.newInstance(Class.java:261)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
java.lang.Thread.run(Thread.java:534)
Then it is not finding zxidjava/libzxidjni.so. Either say
export LD_LIBRARY_PATH=~/zxid-0.14/zxidjava:$LD_LIBRARY_PATH
or place libzxidjni.so in CATALINAHOME/shared/lib. Note that the library name really is libzxidjni.so despite the misleading exception suggesting just "zxidjni".
If you get
java.lang.UnsatisfiedLinkError: Native Library /home/sampo/zxid/zxidjava/libzxidjni.so already loaded in another classloader
java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1551)
java.lang.ClassLoader.loadLibrary(ClassLoader.java:1511)
java.lang.Runtime.loadLibrary0(Runtime.java:788)
java.lang.System.loadLibrary(System.java:834)
zxidhlo.<clinit>(zxidhlo.java:20)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
java.lang.reflect.Constructor.newInstance(Constructor.java:274)
java.lang.Class.newInstance0(Class.java:308)
java.lang.Class.newInstance(Class.java:261)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
java.lang.Thread.run(Thread.java:534)
Then ... ? Currently it seems you have to restart Tomcat.
If you get
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:620)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
java.net.URLClassLoader.access$100(URLClassLoader.java:56)
java.net.URLClassLoader$1.run(URLClassLoader.java:195)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:188)
java.lang.ClassLoader.loadClass(ClassLoader.java:306)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
java.lang.ClassLoader.loadClass(ClassLoader.java:251)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1270)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1201)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
java.lang.Thread.run(Thread.java:595)
Then the problem is with class path. Apparently running the startup.sh script from anywhere else than top level of Tomcat distribution produces the above error.
In case you add debug prints, the stderr (System.err) output appears to go by default to apache-tomcat-5.5.20/logs/catalina.out
Debugging the JNI C code would appear to require running java or jdb under gdb and setting break points in the C code. Unfortunately this appears to be particularly tricky. A possible approach is to introduce a sleep(1) in the C code and then use gdb to attach to the java process. Unfortunately even this method does not seem to allow us to set break points.
export LD_LIBRARY_PATH=zxidjava:$LD_LIBRARY_PATH export QUERY_STRING='e=https%3A%2F%2Fidp.symdemo.com%3A8880%2Fidp.xml&l2=+Login+%28SAML20%3APOST%29+&fc=1&fn=prstnt&fq=&fy=&fa=&fm=exact'
N.B. In following "" means Unix shell prompt, "%" gdb prompt, and ">" jdb prompt.
$ gdb jdb % set env LD_LIBRARY_PATH=zxidjava % set env QUERY_STRING=e=https%3A%2F%2Fidp.symdemo.com%3A8880%2Fidp.xml&l2=+Login+%28SAML20%3APOST%29+&fc=1&fn=prstnt&fq=&fy=&fa=&fm=exact % r zxid > stop at zxid:24 > run > next # or step > print cf > cont
*** TBD: SWIG based, try make csharpzxid
*** TBD: SWIG based, try make rubyzxid
The ZXID library provides two main APIs: the simple and the full. The simple API is meant to get you going with minimal understanding about SAML or SSO. It tries to encapsulate as much control flow as possible.
Consider the follwing "Hello World" CGI example in C
(the zxid_simple() API is available in all language bindings):
01 #include <zx/zxid.h>
02 #define CONF "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxid"
03 void main() {
04 char* res = zxid_simple(CONF, 0, 255);
05 switch (res[0]) {
06 case 'd': /* Logged in case */
07 my_parse_ldif(res);
08 my_render_content();
09 exit(0);
10 default:
11 ERR("Unknown zxid_simple() response(%s)", res);
12 }
13 }
What happens here:
The CGI script calls zxid_simple() to handle SAML protocol according to the configuration
The last argument with value 255 tells zxid_simple() to automatically handle redirections, login screen and any other protocol interaction needed to make SSO happen.
If zxid_simple() returns, we have either succeeded in SSO or we have failed (all other cases are handled internally by zxid_simple() which calls exit(2) so it never returns).
In the success case, zxid_simple() returns an LDIF entry (as a nul terminated C string) describing the SSO and the attributes received. For example
dn: idpnid=Pa45XAs2332SDS2asFs,affid=https://idp.demo.com/idp.xml
objectclass: zxidsession
affid: https://idp.demo.com/idp.xml
idpnid: Pa45XAs2332SDS2asFs
authnctxlevel: password
sesid: S12aF3Xi4A
cn: Joe Doe
where
LDAP distinguished name (part of LDIF format). Always first.
Part of LDIF format.
Specifies which IdP was used for SSO
The federated ID, or pseudonym (IdP assigned NameID)
Rough indication of how IdP authenticated user
Session ID, as may be stored in cookie or used for file name in the session cache (/var/zxid/ses)
If this field is not empty and not equal to '-' (single dash), then the controlling appication should take the necessary actions to set the cookie as specified. Namely, the controlling application should create 'Set-Cookie' HTTP response header whose value is the value of the setcookie field. How this is done is environment dependent.
The ZXIDSES (or other as configured) cookie value. For reference.
Common Name. This attribute just exemplifies how any additional attributes the IdP may have set will appear. Typically the LDAP attribute names are used.
The dn line will always be the first. All other lines may appear
in any order. String representation of LDIF was chosen
as it is easy to parse in most programming languages.
The zxid_simple() can be configured in following ways (later ways can override earlier ones).
Built in default configuration
Configuration file, usually /var/zxid/zxid.conf, if any
Configuration string passed as first argument. While configuration string can override all other options (i.e. it is processed last), the PATH specification is parsed before the configuration file is looked up.
Turns out that often the default configuration modified by the configurations string is all you need - you do not need to prepare configuration file.
See section "Configuring and Running" for complete list of configuration options, but generally it is sufficient to specify only a handful:
Where files are kept and configuration file is found.
The URL of the SP
The Common Domain URL (optional, if omitted the Common Domain Cookie processing is disabled)
The auto_flags argument allows you to control which operations should be performed automatically and which should be passed to the calling application, see "Gaining More Control" section, below, for full description of this case.
The auto options can be added together.
Table 2:zxid_simple() AUTO options
| Dec | Hex | Symbol | Description |
|---|---|---|---|
| 1 | 0x01 | ZXID_AUTO_EXIT | Call exit(), 0=return "n", even if auto CGI |
| 2 | 0x02 | ZXID_AUTO_REDIR | Automatically handle redirects, assume CGI (calls exit(2)) |
| 4 | 0x04 | ZXID_AUTO_SOAPC | SOAP response handling, content gen |
| 8 | 0x08 | ZXID_AUTO_SOAPH | SOAP response handling, header gen |
| 16 | 0x10 | ZXID_AUTO_METAC | Metadata response handling, content gen |
| 32 | 0x20 | ZXID_AUTO_METAH | Metadata response handling, header gen |
| 64 | 0x40 | ZXID_AUTO_LOGINC | IdP select / Login page handling, content gen |
| 128 | 0x80 | ZXID_AUTO_LOGINH | IdP select / Login page handling, header gen |
| 256 | 0x100 | ZXID_AUTO_MGMTC | Management page handling, content gen |
| 512 | 0x200 | ZXID_AUTO_MGMTH | Management page handling, header gen |
| 1024 | 0x400 | ZXID_AUTO_FORMF | In idp list and mgmt screen, generate form fields |
| 2048 | 0x800 | ZXID_AUTO_FORMT | In idp list and mgmt screen, wrap the output in |
| 4095 | 0xfff | ZXID_AUTO_ALL | Enable all automatic CGI behaviour. |
| 4096 | 0x1000 | ZXID_AUTO_DEBUG | Enable debugging output to stderr. |
If the AUTO_REDIR flag is true, the LOCATION header is sent to stdout and exit(0) may be called, depending on the AUTO_NOEXIT flag.
The SOAP, META, LOGIN, and MGMT flags follow convention:
HC
00 No automation. Only action letter is returned ("e"=login, "b"=meta, etc.)
01 Content, not wrapped in headers, is returned as a string
10 Headers and content is returned as a string
11 Headers and content are sent to stdout, CGI style and
exit(0) may be called, depending on AUTO_EXIT. Otherwise "n" is returned.
Whether exit(0) is called in 11 case depends on ZXID_AUTO_NOEXIT flag.
How much HTML is generated for Login page and Mgmt page in 01 (content only) mode depends on AUTO_PAGE and AUTO_FORM flags
TF 00 reserved / nothing is generated 01 Only form fields (but not form tag itself) are generated. 10 Complete form is generated 11 Whole page is generated (best support)
When whole page is generated, some templating information is taken from the configuration.
All the HTML before
The HTML fragment to allow login using a new IdP (Auto CoT using IdP URL). Set to empty to hide this possibility.
Message displaying SP Entity ID, in case (technically minded) user needs to know this to establish relationship with an IdP.
Technical parameters that user might want to set, and typically would be allowed to set. May be hidden (not user controllable) or visible.
Create federation (AllowCreate flag)
Name ID format
Persistent (pseudonym)
Transient, temporary pseudonym
Technical parameters that the site administrator should decide and set. Usually hidden fields:
Affiliation ID (usually empty)
Consent obtained by SP for the federation or SSO
No statement about consent
Has been obtained (unspecified way)
Obtained prior to present transaction, e.g. user signed terms and conditions of service
Consent is implicit in the situation where user came to invoke service
Obtained explicitly
Consent can not be obtained
Obtaining consent is not relevant for the SP or service.
Authentication Context (strength of authentication) needed by the SP
Matching rule for authentication strength (usually empty, IdP decides)
Forbid IdP from interacting with the user (IsPassive flag)
Request reauthentication of user (ForceAuthn flag)
The fully automated interface works well for CGI deployment but probably is not appropriate in more complex situations. You can use zxid_simple() without automation and prevent it from accessing the system layer too directly. Consider
01 #define CONF "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxid"
02 int main() {
03 char* res;
04 res = zxid_simple(CONF, getenv("QUERY_STRING"), 0);
05 switch (res[0]) {
06 case 'L': printf("%s", res); exit(0); /* Redirect */
07 case 'C': printf("%s", res); exit(0); /* Content-type + content */
08 case '<': printf("Content-Type: text/html\r\n\r\n%s", res); exit(0);
09 case 'n': exit(0);
10 case 'b': my_send_metadata();
11 case 'e': my_render_login_screen();
12 case 'd': /* Logged in case */
13 my_parse_ldif(res);
14 my_render_content();
15 exit(1);
16 default:
17 ERR("Unknown zxid_simple() response(%s)", res);
18 }
19 }
Here we specify zero as auto_flags, thus all automation is disabled. This means that the res can take more varied shape and the calling application has to be prepared to handle them. The different cases are distinguished by the first character of the res string:
Redirection request (L as in Location header). The full contents of the res is the redirection request, ready to be printed to stdout of a CGI. If you want to handle the redirection some other way, you can parse the string to extract the URL and do your thing. This res is only returned if you did not set ZXID_AUTO_REDIR.
Example:
Location: https://sp1.zxidsp.org:8443/zxid?o=C
Content with Content-type header. The res is ready to be printed to the stdout of a CGI, but if you want to handle it some other way, you can parse the res to extract the header and the actual body.
Example:
CONTENT-TYPE: text/html
<title>Login page</title>
...
Example (metadata):
CONTENT-TYPE: text/xml
<m:EntityDescriptor>
...
Content without headers. This could be HTML content for login page or metadata XML. To know which (and set content type correctly), you would have to parse the content. This res format is only applicable if you did not specify ZXID_AUTO_CTYPE (but did specify ZXID_AUTO_CONTENT).
Do nothing. The operation was somehow handled internally but the exit(2) was not called (e.g. ZXID_AUTO_SOAP was NOT specified). The application should NOT attempt generating any output.
Indication that the application should send SP metadata to the client. This res is only returned if you did not set ZXID_AUTO_META.
Indication that the application should display the login page. Application may use zxid_idp_list() to render the IdP selection area. This res is only returned if you did not set ZXID_AUTO_CONTENT.
Indication that SSO has been completed or that there was an existing valid session in place. The res is an LDIF entry containing attributes that describe the SSO or session. See "Hello World" section for description of the LDIF data.
Usually your application would parse the attributes and then render its application specific content. If you want to render the SSO management form (with logout and defederate buttones), you can call zxid_fed_mgmt().
Although any unknown letter should be interpreted as an error, we follow convention of prefixing errors with an asterisk ("*").
The simplest APIs are easy to use and suitable for CGIs where the program is restarted anew every time. However in situations where the script engine stays alive persistently, it is wasteful to reparse (and reallocate) the configuration every time. Consider following PHP snippet designed to be used with mod_php:
01 # Put this in the PHP initialization (it only needs to run once)
02 dl("php_zxid.so");
03 $conf = "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxiddemo.php";
04 $cf = zxid_new_conf_to_cf($conf);
05 <? # For every page that is accessed
06 $qs = $_SERVER['REQUEST_METHOD'] == 'GET'
07 ? $_SERVER['QUERY_STRING']
08 : file_get_contents('php://input');
09 $res = zxid_simple_cf($cf, -1, $qs, null, 0x1800);
10 switch (substr($res, 0, 1)) {
11 case 'L': header($res); exit; # Redirect
12 case 'n': exit; # already handled
13 case 'b': my_send_metadata();
14 case 'e': my_render_login_screen();
15 case 'd': break; # Logged in case -- fall through
16 default: error_log("Unknown zxid_simple() res(%s)", res); exit;
17 }
18 # *** Parse the LDIF in $res into a hash of attributes (see zxidhlo.php)
19
20 ?>
21 <html><title>Protected content, logged in as <$=$attr['cn']$></title>
22 ...
23 </html>
24 <?
25 function my_render_login_screen()
26 {
27 ?>
28 <html><title>Please Login Using IdP</title>
29 ...
30 <?=zxid_idp_select_cf($cf, 0, 0x1800)?>
31 ...</html>
32 <? exit; }?>
Notes
Line 4 creates a system-wide configuration object that is later used by the other API calls
On line 9 we call zxid_simple_cf() with the created object. The second and third argument specify a buffer or string that contains the CGI form data to parse. This may come from QUERY_STRING of a GET request or from HTTP body of a POST request, as determined on line 8. The -1 means the length of the data should be determined using strlen(3), i.e. C string nul termination. The auto_flags == 0x1800 enables form tag wrapping and debug prints, but otherwise automation is disabled.
Since automation was disabled, we need to handle several cases of possible outcomes from zxid_simple_cf(), on lines 10-17.
From line 18 onwards we handle the login successful or already logged in case. First we split the LDIF entry into a hash so that we can access the attributes easily (e.g. cn on line 20).
On line 30 we call zxid_idp_list_cf() to create the form for choosing which IdP to use for login (remember that auto_flags == 0xc0 enabled the form wrapper). As can be seen the same configuration object, $cf, is used through out.
Consider
01 import zxidjava.*;
02 import java.io.*;
03 import javax.servlet.*;
04 import javax.servlet.http.*;
05 public class zxidhlo extends HttpServlet {
06 static { System.loadLibrary("zxidjni"); }
07 static final String conf
08 = "PATH=/var/zxid/&URL=http://sp1.zxidsp.org:8080/zxidservlet/zxidHLO";
09 public void do_zxid(HttpServletRequest req, HttpServletResponse res, String qs)
10 throws ServletException, IOException {
11 String ret = zxidjni.simple(conf, qs, 0xd54);
12 switch (ret.charAt(0)) {
13 case 'L': /* Redirect: ret == "LOCATION: urlCRLF2" */
14 res.sendRedirect(ret.substring(10, ret.length() - 4));
15 return;
16 case '<':
17 switch (ret.charAt(1)) {
18 case 's': /* <se: SOAP envelope */
19 case 'm': /* <m20: metadata */
20 res.setContentType("text/xml");
21 break;
22 default:
23 res.setContentType("text/html");
24 break;
25 }
26 res.setContentLength(ret.length());
27 res.getOutputStream().print(ret);
28 break;
29 case 'd': /* Logged in case */
30 //my_parse_ldif(res);
31 res.setContentType("text/html");
32 res.getOutputStream().print(zxidjni.fed_mgmt(conf, 0xd54));
33 break;
34 default:
35 System.err.print("Unknown zxid_simple() response:");
36 System.err.print(ret);
37 }
38 }
39 public void doGet(HttpServletRequest req, HttpServletResponse res)
40 throws ServletException, IOException {
41 // LECP/ECP PAOS header checks
42 do_zxid(req, res, req.getQueryString());
43 }
44 public void doPost(HttpServletRequest req, HttpServletResponse res)
45 throws ServletException, IOException {
46 String qs;
47 int len = req.getContentLength();
48 byte[] b = new byte[len];
49 int got = req.getInputStream().read(b, 0, len);
50 qs = new String(b, 0, got);
51 do_zxid(req, res, qs);
52 }
53 }
Any Bourne shell (Unix shell) shell script can be converted to a SAML SSO enabled CGI script using zxidsimple(1) helper utility. The program simply wraps the zxid_simple() API function so that the inputs can be provided as command line arguments, or in case of qs as stdin, and the output is returned on stdout.
Synopsis
zxidsimple -o ldif CONF AUTO_FLAGS <cgi-input
Typical usage (see also zxidhlo.sh):
CONF="PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxidhlo.sh"
./zxidsimple -o /tmp/zxidhlo.sh.$$ $CONF 4094 || exit;
IFS="
"
res=`cat /tmp/zxidhlo.sh.$$`
case "$res" in
dn*)
for x in $res; do
case "$x" in
sesid:*) SID=${x##*sesid: } ;;
idpnid:*) NID=${x##*idpnid: } ;;
cn:*) CN=${x##*cn: } ;;
esac
done
;;
*) echo "ERROR($res)" >>/tmp/hlo.err; exit ;;
esac
cat << EOF
Content-Type: text/html
<title>ZXID HELLO SP Mgmt</title>
<h1>ZXID HELLO SP Management (user $CN logged in, session active)</h1>
<form method=post action="zxidhlo.sh?o=P">
<input type=hidden name=s value="$SID">
<input type=submit name=gl value=" Local Logout ">
<input type=submit name=gr value=" Single Logout (Redir) ">
</form>
EOF
The zxidsimple(1) utility will return exit value 1 if it handled a SAML protocol operation (by outputting to stdout whatever was appropriate). The shell script should not do any further processing and just exit.
If the exit value is 0 (success) then SSO has been done. Since the attributes from the SAML assertion are usually interesting, you can capture them to a temporary file using the -o option.
First we split the result of the backtick into a list on (literal) newline. Then we process the list with for loop and look with case for the interesting attributes and capture them into local variables.
Finally the protected content page is output.
The ZXID cgi interface assumes certain hardwired form field names. These are not configurable (and there is no intent to make them configurable). The cgi fields may appear either in query string (GET method) or as POST content (though depending on your programming environment and language, you may need to read the POST data in yourself prior to calling zxid_simple()).
Operation. In particular o=P means that form uses POST method.
Session ID
SAML 2.0 mandated field name for relay state
SAML 2.0 mandated field name for SAML artifact
SAML 2.0 mandated field name for SAML response, especially in POST profile
SAML 2.0 mandated field name for SAML request
SAML 2.0 mandated field name for signature algorithm in redirect binding
SAML 2.0 mandated field name for signature in redirect binding
User (local login)
Password (local login)
Common Domain Cookie
Entity ID (manual entry field)
Entity ID (from popup or radio box)
Protocol index
Login using artifact profile (same as i=1)
Login using POST profile (same as i=2)
Login using specified IdP (artifact profile), same as e=EID&i=1
Login using specified IdP (POST profile), same as e=EID&i=2
Allow Create flag
IsPassive flag
Force Authentication flag
NameID format
Affiliation ID
Consent field
Matching rule
Authentication Context Class
Relay State
The IdP selection form (aka Login) screen can be implemented, using the above documented form interface, in many ways as following examples illustrate.
Example IdP Selection Form: Popup menu method
***
Example IdP Selection Form: Separate IdP buttons method
<form method=post
action="http://sp1.zxidsp.org:8080/zxidservlet/zxidHLO?o=P">
<h3>Login Using New IdP</h3>
<p>IdP URL <input name=e size=80>
<input type=submit name=l1 value=" Login (A2) ">
<input type=submit name=l2 value=" Login (P2) "><br>
<h3>Login Using Known IdP</h3>
<input type=submit name="l1https://a-idp.liberty-iop.org:8881/idp.xml"
value=" Login to https://a-idp.liberty-iop.org:8881/idp.xml (A2) ">
<input type=submit name="l2https://a-idp.liberty-iop.org:8881/idp.xml"
value=" Login to https://a-idp.liberty-iop.org:8881/idp.xml (P2) ">
<h3>Technical options</h3>
<input type=checkbox name=fc value=1 checked> Create federation,
NID Format: <select name=fn>
<option value=prstnt>Persistent
<option value=trnsnt>Transient
<option value="">(none)
</select><br>
<input type=hidden name=fq value="">
<input type=hidden name=fy value="">
<input type=hidden name=fa value="">
<input type=hidden name=fm value="">
<input type=hidden name=fp value=0>
<input type=hidden name=ff value=0>
</form>
Example IdP Selection Form: IdP links method
***
Local Logout
Single Logout using redirection
Single Logout using SOAP
NameID Managment (redirect)
NameID Management (SOAP)
Example Management Form
<form method=post action="zxid?o=P"> <input type=hidden name=s value=""> <input type=submit name=gl value=" Local Logout "> <input type=submit name=gr value=" Single Logout (Redir) "> <input type=submit name=gs value=" Single Logout (SOAP) "> <input type=submit name=gt value=" Defederate (Redir) "> <input type=submit name=gu value=" Defederate (SOAP) "> </form>
Single Sign-On is used to protect some useful resources. ZXID does not have any means of serving these resources, rather a normal web server or application server should do it. ZXID should just concentrate on verifying that a user has valid session, and if not, establishing the session by way of SSO.
The SAML 2.0 specifications mandate a wire protocol, and in order to speak the wire protocol, the SP application typically has to follow certain standard sequence of control flow.

Fig-2: Typical control flow of ZXID SP
First a user
tries to access a web site that acts in SP role. This
triggers following sequence of events
User is redirected to URL in a common domain. This is so that we can read the Common Domain Cookie that indicates which IdP the user uses. Alternatively, if you started at https://sp1.zxidsp.org:8443/zxid?o=E, the CDC check is by-passed and flow 2b. happens.
After the CDC check, a Authentication Request (AuthnReq) is generated. The IdP may have been chosen automatically using CDC (2a), or there may have been some user interface interaction (not show in the diagram) to choose the IdP.
User is redirected to the IdP. The redirection carries as a query string a compressed and encoded form of the SAML 2.0 AuthnReq.
Once the IdP has authenticated the user, or observed that there already is a valid IdP session (perhaps from a cookie), the IdP redirects the user back to the SP.
The AuthnResponse may be carried in this redirection in a number of alternate ways
The redirect contains a special token called artifact. The artifact is a reference to the AuthnResponse and the SP needs to get the actual AuthnResponse by using a SOAP call (the 4bis step).
The "redirect" is actually a HTML page with a form and little JavaScript that causes the form to be automatically posted to the SP. The AuthnResponse is carried as a form field.
After verifying that AuthnResponse indicated a success, the SP establishes a local session for the user (perhaps setting a cookie to indicate this).
Depending on how the SP to web site integration is done the user is taken to the web site in one of the two ways
Redirect to the content. This time the session is there, therefore the flow passes directly from check session to the web content.
It is also possible to show the content directly without any intervening redirection.
The generated aspects of the native C API are in c/*-data.h, for example
c/zx-sa-data.h
Studying this file is very instructive.
From .sg a header (NN-data.h) is generated. This header contains structs that
represent the data of the elements. Each element and attribute
generates its own node. Even trivial nodes like strings have to be
kept this way because the nodes form basis of remembering the ordering
of data. This ordering is needed for exclusive XML canonicalization,
and thus for signature verification.
Any missing data is represented by NULL pointer.
Any repeating data is kept as a linked list, in reverse order of being
seen in the data stream.
Simple elements and all attributes are represented by simple string node (even if they are booleans or integers).
Example
Consider following XML
<ds:Signature>
<ds:SignedInfo>
<ds:CanonicalizationMethod
Algorithm="http://w3.org/xml-exc-c14n#"/>
<ds:SignatureMethod
Algorithm="http://w3.org/xmldsig#rsa-sha1"/>
<ds:Reference
URI="#RrcrNwFIw6n">
<ds:Transforms>
<ds:Transform
Algorithm="http://w3.org/xml-exc-c14n#"/>
<ds:Transform
Algorithm="http://w3.org/xmldsig#env-sig"/></>
<ds:DigestMethod
Algorithm="http://w3.org/xmldsig#sha1"/>
<ds:DigestValue>lNIzVMrp8CwTE=</></></>
<ds:SignatureValue>
GeMp7LS...vnjn8=</></>
Decoding would produce the data structure in Fig-3. You should also look at c/zx-sa-data.h to see the structs involved in this example.

Fig-3: Typical data structure produced by decode.
There are two pointer systems at play here. The black solid arrows
depict the logical structure of the XML document. For each child
element there is a struct field that simply points to the child. If
there are multiple occurrences of the child, as in
sig->SignedInfo->Reference->Transforms->Transform, the children are
kept in a linked list connected by gg.g.n (next) fields.
The wide order structure, depicted by red dashed arrows, is maintained using gg.kids and gg.g.wo fields. For example sig->SignedInfo->Reference->Transforms keeps its kids, the zx_ds_Transform objects, in the original order hanging from the kids and linked with the wo field. As can be seen, the order kept with wo fields can be different than the one kept using n (next) fields. What's more, the kids list can contain dissimilar objects, witness sig->SignedInfo->Reference->gg.kids. The wire order representation is only captured when decoding the document and is mainly useful for correctly canonicalizing the document for signature verification. If you are building a data structure in your own program, you typically will not set the gg.kids and gg.g.wo fields.
In the diagram, the objects of type zx_str were collapsed to
double quoted strings. Superfluous gg.kids, gg.g.wo, and gg.g.n fields
were omitted: they exist in all structures, but are not shown when
they are NULL. The NULL is depicted as zero (0).
An annoying feature of XML documents is that they have variable namespace prefixes. The namespace prefix for the unqualified elements is taken to be the one specified in target() directive of the .sg input. Name of an element in C code is formed by prefixing the element by the namespace prefix and an underscore.
Attributes will only have namespace prefix if such was expressly specified in .sg input.
When decoding, the actual namespace prefixes are recorded. The wire order encoder knows to use these recorded prefixes so that accurate canonicalization for XMLDSIG can be produced.
If the message on wire uses wrong namespaces, the wrong ones are remembered so that canonicalization for signature validation will work irrespective. The ability to accept wrong namespaces only works as long as there is no ambiguity as to which tag was meant - there are some tags that need namespace information to distinguish. If you hit one of these then either you get lucky and the one that is arbitrarily picked by the decoder happens to be the correct one, or you are stuck with no easy way to make it right. Of course the XML document was wrong to start with so theoretically this is not a concern. Generally the more schemata that are simultaneously generated to one package, the greater the risk of collisions between tags.
The schema order encoder always uses the prefixes defined using target() directives in .sg files. The runtime notion of namespaces is handled by ns_tab field of the decoding and encoding context. It is initialized to contain all namespaces known by virtue of .sg declarations. The runtime assigned prefixes are held in a linked list hanging from n (next) field of struct zx_ns_s.
The code generation creates a file, such as c/zx-ns.c, which contains initialization for the table. The main program should point the ns_tab field of context as follows:
main {
struct zx_ctx* ctx;
...
ctx->ns_tab = zx_ns_tab; /* Here zx_ is the chosen prefix */
}
Consider the following evil contortion
<e:E xmlns:e="uri">
<h:H xmlns:h="uri"/>
<b:B xmlns:b="uri">
<e:C xmlns:e="uri"/>
<e:D xmlns:e="iru">
<e:F xmlns:e="uri"/></></></>
Assuming the ns_tab assigns prefix y to the namespace URI, we would have following data structure as a result of a decode

Fig-4: Decode of XML and resulting namespace structures.
The red thin arrows indicate how the elements reference the namespaces. Since none of the elements used the prefix originally specified in the schema grammar target() directive, we ended up allocating "alias" nodes for the uri. However, since E and C use the same prefix, they share the alias node. Things get interesting with D: it redefines the prefix e to mean different namespace URI, "iru", which happens to be an alias of prefix z.
Later, when wire order canonical encode is done, the red thin arrows are chased to determine the namespaces. However, we need to keep a separate "seen" stack to track whether parent has already declared the prefix and URI. E would declare xmlns:e="uri", but C would not because it had already been "seen". However, F would have to declare it again because the xmlns:e="iru" in D masks the declaration. The zx_ctx structure is used to track the namespaces and "seen" status through out decoders and encoders.

Fig-5: Seen data structure (blue dotted and green dashed arrows) in the end of decoding F. S=seen, SN=seen_n.
Here we can see how the seen_n list, represented by the blue dotted
arrows, was built: at the head of the list, ctx->seen_n, is the last
seen prefix, namely b (because, although the meaning of e at F was
different, e as a prefix had already been seen earlier at E), followed
by other prefixes in inverse order of first occurrence.
The green dashed arrows from
e:uri to e:iru and then on to second e:uri reflect the fact that e:uri
(second) was put to the list first (when we were at E), but later, at
D, a different meaning, iru, was given to prefix e. Finally at F we
give again a different meaning for e, thus pushing to the "seen stack"
another node. Although e at E and at F have namespace URI, "uri", we are
not able to use the same node because we need to keep the stack order.
Thus we are forced to allocate two identical nodes.
Since our aim is to be lax in what we accept, every element can handle unexpected additional attributes as well as unexpected elements. Thus whether the schema specifies any or anyAttribute or not, we handle everything as if they were there. However, when attributes and elements are received outside of their expected context, they are simply treated as strings with string names. This is true even for those attributes and elements that would be recognizable in their proper context.
The any extension points, as well as some bookkeeping data are hidden inside ZX_ELEM_EXT macro. If you tinker with this macro, be sure you know what you are doing. If you want to add your own specific fields to all structs, redefining ZX_ELEM_EXT may be appropriate, but if you want to add more fields only to some specific structures, you can define a macro of form
TPF_EEE_EXT
and put in it whatever fields you want. These fields will be initialized to zero when the structure is created, but are not touched in any other way by the generated code. In particular, if some of your fields are pointers, it will be your responsibility to free them. The standard free functions will not understand to free them. See the data structure walking functions, below for one way to accomplish this.
The root data structure
struct zx_root_s;
is a special structure that has a field for every top level recognizable element.
*** TBW
After decoding all string data points directly into the input buffer, i.e. strings are NOT copied. Be sure to not free the input buffer until you are done processing the data structure. If you need to take a copy of the strings, you will need to walk the data structure as a post processing step and do your copies. This can be done using
void TPF_dup_strs_len_NS_EEE(struct zx_dec_ctx* c, struct TPF_NS_EEE_s* x);
The structures are allocated via ZX_ZALLOC() macro, which by default calls zx_zalloc() function, which in turn uses system malloc(3). However, you can redefine the macro to use whatever other allocation scheme you desire.
The generated libraries never free(3) memory. In many programming patterns, this is actually desirable: for example a CGI program can count on dying - the process exit(2) will free all the memory.
If you need to free(3) the data structure, you will need to walk it using
void TPF_free_len_NS_EEE(struct zx_dec_ctx* c,
struct TPF_NS_EEE_s* x,
int free_strings);
void zx_free_any(struct zx_dec_ctx* c,
struct zx_note_s* n,
int free_strs);
The zx_free_any() works by having a gigantic switch statement that calls the appropriate specific free function.
You can deep clone the data structure with
void TPF_deep_clone_NS_EEE(struct zx_dec_ctx* c,
struct TPF_NS_EEE_s* x,
int dup_strings);
struct zx_note_s* zx_clone_any(struct zx_dec_ctx* c,
struct zx_note_s* n,
int dup_strs);
The zx_clone_any() works by having a gigantic switch statement that calls the appropriate specific free function.
The entry point to the decoder is
struct zx_root_s* zx_DEC_root(struct zx_dec_ctx* c,
struct zx_ns_s* dummy,
int n_decode);
The decoding context holds pointer to the raw data and must be
initialized prior to calling the decoder. The third argument specifies
how many recognized elements are decoded before returning. Usually you
would specify 1 to consume one top level element from the
stream.
The returned data structure, struct zx_root_s, contains one pointer for each type of top level element that can be recognized. The tok field of the returned value identifies the last top level element recognized and can be used to dispatch to correct request handler:
zx_prepare_dec_ctx(c, TPF_ns_tab, start_ptr, end_ptr);
struct TPF_root_s* x = TPF_DEC_root(c, 0, 1);
switch (x->gg.g.tok) {
case TPF_NS_EEE_ELEM: return process_EEE_req(x->NN_EEE);
}
When processing responses, it is generally already known which type of response you are expecting, so you can simply check for NULLness of the respective pointer in the returned data structure.
Internally zx_DEC_root() works much the same way: it scans a beginning of an element from the stream, looks up the token number corresponding to the element name, and switches on that, calling element specific decoder functions (see next section) to do the detailed processing.
In the above code fragment, you should note the call to zx_prepare_dec_ctx() which initializes the decoder machinery. It takes ns_tab argument, which specifies which namespaces will be recognized. This table MUST match the TPF_DEC_root() function you call (i.e. both must have been generated as part of the same xsd2sg.pl invocation). The other arguments are the start of the buffer to decode and pointer one past the end of the buffer to decode.
For each recognizable element there is a function of form
struct TPF_NS_EEE_s* zx_DEC_NS_EEE(struct zx_dec_ctx* c);
where TPF is the prefix, NS is the namespace prefix, and EEE is the element name. For example:
struct zx_se_Envelope_s* zx_DEC_se_Envelope(struct zx_ctx* c);
These functions work much the same way as the root decoder. You should consult dec-templ.c for the skeleton of the decoder. Generally you should not be calling element specific decoders: they exist so that zx_DEC_root() can call them. They have somewhat nonintuitive requirements, for example the opening <, the namespace prefix, and the element name must have already been scanned from the input stream by the time you call element specific decoder.
The generated code is instrumented with following macros
Extension point called just after decoding known attribute
Extension point called just after decoding xmlns attribute
Extension point called just after decoding unknown attr
Extension point called just after decoding element name and allocating struct, but before decoding any of the attributes.
Extension point called just after decoding the entire element.
Extension point called just after decoding element tag, including attributes, but before decoding the body of the element.
Extension point called just after decoding processing instruction
Extension point called just after decoding comment
Extension point called just after decoding string content
Extension point called just after decoding unknown element
Following macros are available to the extension points
Type prefix (as specified by -p during code generation)
Namespaceful element name (NS_EEE)
Name of the struct that describes the element
Namespace prefix of the element (as seen in input schema)
Name of the element without any namespace qualification.
The encoder receives a C data structure and generates a gigantic string containing an XML document corresponding to the data structure and the input schemata. The XML document conforms to the rules of exclusive XML canonicalization and hence is useful as input to XMLDSIG.
One encoder is generated for each root node specified at the code generation. Often these encoders share code for interior nodes.
The encoders allow two pass rendering. You can first use the length computation method to calculate the amount of storage needed and then call one of the rendering functions to actually render. Or if you simply have large enough buffer, you can just render directly.
The encoders take as argument next free position in buffer
and return a char pointer one past the last byte used. Thus
you can discover the length after rendering by subtracting the
pointers. This is guaranteed to result same length as returned
by the length computation method.
You can also call the next encoder with the return value
of the previous encoder to render back-to-back elements.
The XML namespace and XML attribute handling of the encoders is novel in that the specified sort is done already at code generation time, i.e. the renderers are already in the order that the sort mandates.
For attributes we know the sort order directly from the schema because [XML-C14N], sec 2.2, p.7, specifies that they sort first by namespace URI and then by name, bot of which we know from the schema.
For xmlns specifications the situation is similarly easy in the schema order encoder case because we know the namespace prefixes already at code generation time. However, for the wire order encoder we actually need a runtime sort because we can not control which namespace prefixes get used. However, for both cases we can make a pretty good guess about which namespaces might need to be declared at any given element: the element's own namespace and namespaces of each of its attributes. That's all, and it's all known at code generation time. At runtime we only need to check if the namespace has already been seen at outer layer.
Compute length of an element (and its subelements). The XML attributes and elements are processed in schema order.
int TPF_LEN_SO_NS_EEE(struct zx_ctx* c,
struct TPF_NS_EEE_s* x);
For example:
int zx_LEN_SO_se_Envelope(struct zx_ctx* c,
struct zx_se_Envelope_s* x);
Compute length of an element (and its subelements). The XML namespaces and elements are processed in wire order.
int TPF_LEN_WO_NS_EEE(struct zx_ctx* c,
struct TPF_NS_EEE_s* x);
For example:
int zx_LEN_WO_se_Envelope(struct zx_ctx* c,
struct zx_se_Envelope_s* x);
Render an element into string. The XML elements are processed in
schema order. The xmlns declarations and XML attributes are always
sorted per [XML-EXC-C14N] rules.
This is what you
generally want for rendering new data structure to a string. The wo
pointers are not used.
char* TPF_ENC_SO_NS_EEE(struct zx_ctx* c,
struct TPF_NS_EEE_s* x,
char* p);
For example:
char* zx_ENC_SO_se_Envelope(struct zx_ctx* c,
struct zx_se_Envelope_s* x,
char* p);
Since it is a very common requirement to allocate correct sized buffer and then render an element, a helper function is provided to do this in one step.
struct zx_str* zx_EASY_ENC_SO_se_Envelope(struct zx_ctx* c,
struct zx_se_Envelope_s* x);
The returned string is allocated from allocation arena described by zx_ctx.
Render element into string. The XML elements are processed in wire order by chasing wo pointers. This is what you want for validating signatures on other people's XML documents. If the wire representation was schema invalid, e.g. elements were in wrong order, the wire representation is still respected, except for xmlns declarations and XML attributes, which are always sorted, per exc-c14n rules. For each element a function is generated as follows
char* TPF_ENC_WO_NS_EEE(struct zx_ctx* c,
struct TPF_NS_EEE_s* x,
char* p);
For example
char* zx_ENC_WO_se_Envelope(struct zx_ctx* c,
struct zx_se_Envelope_s* x,
char* p);
A helper function is also available
struct zx_str* zx_EASY_ENC_WO_se_Envelope(struct zx_ctx* c,
struct zx_se_Envelope_s* x);
*** TBW
For signature validation you need to walk the decoded data structure
to locate the signature as well as the references and pass them to
zxsig_validate(). The validation involves wire order exclusive
canonical encoding of the referenced XML blobs, computation of SHA1 or
MD5 checksums over them, and finally computation of SHA1 check sum
over the
A nasty problem in exclusive canonicalization is that the namespaces
that are needed in the blob may actually appear in the containing XML
structures, thus in order to know the correct meaning of a namespace
prefix, we need to perform the seen computation for all elements
outside and above the blob of interest.
To verify signature, you have to do certain amount of preparatory work to locate the signature and the data that was signed. Generally what should be signed will be evident from protocol specifications or from the security requirements of your application environment. Conversely, if there is a signature, but it does not reference the appropriate elements, its worthless and you might as well reject the document without even verifying the signature.
Example
struct zxsig_ref refs[1];
cf = zxid_new_conf("/var/zxid/");
ent = zxid_get_ent_from_file(cf, "YV7HPtu3bfqW3I4W_DZr-_DKMP4.");
refs[0].ref = r->Envelope->Body->ArtifactResolve
->Signature->SignedInfo->Reference;
refs[0].blob = (struct zx_elem_s*)r->Envelope->Body->ArtifactResolve;
res = zxsig_validate(cf->ctx, ent->sign_cert,
r->Envelope->Body->ArtifactResolve->Signature,
1, refs);
if (res == ZXSIG_OK) {
D("sig vfy ok %d", res);
} else {
ERR("sig vfy failed due to(%d)", res);
}
This code illustrates
You have to determine who signed and provide the entity object that corresponds to the signer. Often you
would determine the entity from
The entity is used for retrieving the signing certificate.
Another alternative is that the signature itself contains
a
You have to prepare the refs array. It contains pairs of
In the above example, locating the one signed bit was very easy: the specification says where it is (and this location is fixed so there really is no need to check the URI either).
You pass the length of the refs array and the array itself as two last arguments to zxsig_validate().
You need to locate the
The return value will indicate validation status. ZXSIG_OK, which has numerical value of 0, indicates success. Other nonzero values indicate various kinds of failure.
Trust models for TLS and signature validation are separate. TLS layer is handled mainly by libcurl or in case of ClientTLS, by the https web server (which is not part of zxid).
In signature validation the primary trust mechanism is that entity's
metadata specifies the signing certificate and there is no
Certification Authority check at all.
This model works well if you control the admission
to your CoT. However, ZXID ships by default with the
automatic CoT feature turned on, thus anyone can get
added to the CoT and therefore signature with any
certificate they declare is "valid". This hardly
is acceptable for anything involving money.
Simple read access to data should, in C, be done by simply referencing the fields of the struct, e.g.
if (!r->EntitiesDescriptor->EntityDescriptor)
goto bad_md;
*** TBW
*** TBW
*** TBW
All generated libraries are designed to be thread safe, provided that the underlying libc APIs, such as malloc(3) are thread safe.
Calling an ID Web Service requires an Endpoint Reference (EPR) that
indicates not only the URL of the web service, but also the security
mechanism and any tokens or credentials required by the security
mechanism, collectively called the metadata of the EPR.
An EPR can be obtained from two sources
From the SSO assertion containing an attribute statement that has the EPR. This is called the bootstrap method.
By calling the discovery service.
Either way, the EPRs are cached in the SSO session as files with paths like
/var/zxid/ses/SESID/SVCTYPE,SHA1
where SESID is the SSO session ID (safe base64 of a random number). SVCTYPE and SHA1 form a unique file name inside the session directory. SVCTYPE component allows easy identification of the EPRs that are relevant for calling a given service. The SHA1 component is a SHA1 hash over the canonical XML representation of the EPR.
When bootstrap EPRs are present in the SSO assertion, they are automatically extracted to the EPR cache (internally zxid_snarf_eprs_from_ses() is called). Generally this will yield at least bootstrap EPR for discovery service. Later, when calling web services, discovery is automatically performed as needed and the results are automatically populated to the EPR cache (internally zxid_cache_epr() is called).
When calling higher level WSC APIs, the discovery will happen automatically, but if you work in terms of lower level APIs, you can obtain an EPR by calling zxid_get_epr() which will first consult the cache, and if there is a miss, then try discovering the EPR using discovery service EPR, if any (usually one was obtained as bootstrap during the SSO).
The high level API is based on the idea of constructing the SOAB body (the payload) as a string and passing that to function that performs the SOAP call and returns response.
01 cf = zxid_new_conf_to_cf(CONF);
02
03 res = zxid_simple_cf(cf, cl, qs2, 0, 0x1fff);
04 switch (res[0]) {
05 default:
06 ERR("Unknown zxid_simple() response(%s)", res);
07 case 'd': break; /* Logged in case */
08 }
09 sid = strstr(res, "sesid: ");
10 zxid_get_ses(cf, &sess, sid);
11 env = zxid_callf(cf, &sess, zx_xmlns_idhrxml,
12 "<idhrxml:Modify>"
13 "<idhrxml:ModifyItem>"
14 "<idhrxml:Select>%s</idhrxml:Select>"
15 "<idhrxml:NewData>%s</idhrxml:NewData>"
16 "</idhrxml:ModifyItem>"
17 "</idhrxml:Modify>", cgi.select, cgi.data);
18 ZXID_CHK_STATUS(env, idhrxml_ModifyResponse,
19 hrxml_resp = "Modify failed"; break);
20 hrxml_resp = "Modify OK";
On lines 1-10 a single sign on is done to prepare the session and EPR cache.
env = zxid_callf(cf, ses, svctype, fmt, ...)
zxid_callf() first creates the body of the SOAP call by expanding the format string (which may involve additional arguments). Next it parses the string into XML data structure. If the format string uses unresolved namespaces, they are resolved using the svctype argument.
Next zxid_callf() will attempt to locate an EPR for the service type. This may already be in cache, or discovery step may be performed.
Then zxid_callf() augments the XML data structure with Liberty ID-WSF mandated headers. It will look at the security mechanism and token specified in the EPR and perform appropriate steps to create WS-Security header and apply signature as needed.
Finally a SOAP call is made. The result is XML parsed and returned as SOAP envelope object.
Configuration object, see zxid_new_conf_to_cf()
Session object, used to locate EPRs, see zxid_get_ses()
Service type and namespace that is applicable to the body. This is one of the constants from c/zx-ns.h
printf style format string that is used to describe the body of the call as a string. If fmt contains format specifiers, then additional arguments are used to expand these.
SOAP envelope structure.
N.B. Although the request body is formulated as a string, you can only use XML constructs whose schema is known to ZXID. The resulting XML must be validly parseable by ZXID.
ZXID_CHK_STATUS(env, resp_tag, abort-action); ZXID_CHK_STATUS(env, idhrxml_ModifyResponse, break);
In ID-WSF web services it is very common that the overall
outcome of the operation is expressed by
If status is NOT "OK", then abort-action is invoked. This would be whatever needed in your program to report error and abort further processing of the response. It could be a break, return, or even a goto statement.
SOAP envelope representing the response
The response tag as it appears as a child of env->Body
Statement, or statements, used to report error and abort processing.
There is no return value. This macro is "procedural".
Typical code for calling a web service at low level
01 #include <zx/errmac.h>
02 #include <zx/zxid.h>
03 #include <zx/zxidconf.h>
04 #include <zx/saml2.h>
05 #include <zx/wsf.h>
06 #include <zx/c/zx-ns.h>
07
08 struct zx_e_Envelope_s* env;
09 struct zx_a_EndpointReference_s* epr;
10 epr = zxid_get_epr(cf, ses, zx_xmlns_dap, 1);
11 if (epr) {
12 env = zx_NEW_e_Envelope(cf->ctx);
13 env->Header = zx_NEW_e_Header(cf->ctx);
14 env->Body = zx_NEW_e_Body(cf->ctx);
15 env->Body->Query = zxid_mk_dap_query(cf, ...); /* See ID-DAP inteface */
16 env = zxid_wsc_call(cf, ses, epr, env); /* The beef */
17 if (env->dap_QueryResponse)
18 D("Result is LDIF(%.*s)",
19 env->Body->dap_QueryResponse->Data->LDIF->gg.content->len,
20 env->Body->dap_QueryResponse->Data->LDIF->gg.content->s);
21 }
On line 10 zxid_get_epr() is used with following arguments
Configuration object
Session object (generallly obtained from SSO)
The service type of the service that is to be called. Generally this is same as the namespace
URI. The include
The last argument ("1", one) is an iterator index that, in case of multiple EPRs allows you to pick which one to use.
Most common usage is to simply supply 1 which picks
the first one.
epr = zxid_get_epr(cf, ses, svctype, n);
See if an EPR for service svctype is available in current session EPR cache. If not, see if discovery EPR is available and try to discover the EPR for the svctype. Note that the discovery is transparent to the programmer - indeed programmer can not know whether EPR was served from cache (where it may have appeared by virtue of a bootstrap) or whether it was discovered.
Configuration object, see zxid_new_conf_to_cf()
Session object, used to locate EPRs in cache, see zxid_get_ses()
Service type (usually namespace of the service). This is one of the constants from c/zx-ns.h
Ordinal. If more than one EPR is available, specifies which one is desired. Usually 1 is supplied, to pick the first EPR.
An EPR object (URL of the service, security mechanism, and possibly security token (SAML assertion)).
The ID-DAP search filters and data model are very similar to LDAP, see [RFC2251] for further explanation.
env->Body->dap_Query
= zxid_mk_dap_query(cf,
0, /* No tests */
zxid_mk_dap_query_item(cf,
zxid_mk_dap_select(cf,
0, /* DN from ID-WSF */
"objecttype=svcprofile",
0, /* all attributes */
1, /* chase symlinks */
ZXID_DAP_SCOPE_SUBTREE,
0, /* no size limit */
0, /* no time limit */
0), /* return data */
0, /* regular data entries */
0, /* No predefined operation */
0, /* No sorting. */
0, /* No changed since specification. */
0, /* Do not include LDAP common attributes. */
0, /* Start from first result (offset == 0) */
0, /* Return all results (count == 0) */
0, /* Do not request snapshot */
0, /* Do not refer to snapshot */
0), /* No contingent item ID reference */
0); /* No subscriptions */
As can be seen, it is common to specify nearly all arguments as 0, relying on default values. Thus the code typically appears without comments as
env->Body->dap_Query
= zxid_mk_dap_query(cf, 0,
zxid_mk_dap_query_item(cf,
zxid_mk_dap_select(cf, 0, "objecttype=svcprofile",
0, 1, ZXID_DAP_SCOPE_SUBTREE, 0, 0, 0),
0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 10 zeroes here */
0); /* No subscriptions */
As a query can also have test and subscription clauses, the fully winded example becomes quite onerous. Of course for many daily tasks you will not need all the frills, or you can just use the simple API instead.
env->Body->dap_Query
= zxid_mk_dap_query(cf,
zxid_mk_dap_test_item(cf,
zxid_mk_dap_testop(cf,
0, /* DN from ID-WSF */
"objecttype=svcprofile",
0, /* all attributes */
1, /* chase symlinks */
ZXID_DAP_SCOPE_SUBTREE,
0, /* no size limit */
0, /* no time limit */
0), /* return data */
0, /* regular data entries */
0), /* No predefined operation */
zxid_mk_dap_query_item(cf,
zxid_mk_dap_select(cf,
0, /* DN from ID-WSF */
"objecttype=svcprofile",
0, /* all attributes */
1, /* chase symlinks */
ZXID_DAP_SCOPE_SUBTREE,
0, /* no size limit */
0, /* no time limit */
0), /* return data */
0, /* regular data entries */
0, /* No predefined operation */
0, /* No sorting. */
0, /* No changed since specification. */
0, /* Do not include LDAP common attributes. */
0, /* Start from first result (offset == 0) */
0, /* Return all results (count == 0) */
0, /* Do not request snapshot */
0, /* Do not refer to snapshot */
0), /* No contingent item ID reference */
zxid_mk_dap_subscription(cf,
"subsID",
0, /* No item ID reference */
zxid_mk_dap_resquery(cf,
zxid_mk_dap_select(cf,
0, /* DN from ID-WSF */
"objecttype=svcprofile",
0, /* all attributes */
1, /* chase symlinks */
ZXID_DAP_SCOPE_SUBTREE,
0, /* no size limit */
0, /* no time limit */
0), /* return data */
0, /* regular data entries */
0, /* No predefined operation */
0, /* No sorting. */
0, /* No changed since specification. */
0, /* Do not include LDAP common attributes. */
0), /* No contingent item ID reference */
0, /* No notification aggregation spec. */
0, /* No notification trigger spec. */
0, /* Subscription starts immediately. */
0, /* Subscription never expires. */
1, /* Include changed data in the notifications. */
0, /* Use notification reference for administrative notifications. */
"http://host/notif_sink")
);
struct zx_dap_Query_s* zxid_mk_dap_query(struct zxid_conf* cf,
struct zx_dap_TestItem_s* tis,
struct zx_dap_QueryItem_s* qis,
struct zx_dap_Subscription_s* subs);
struct zx_dap_QueryItem_s* zxid_mk_dap_query_item(struct zxid_conf* cf,
struct zx_dap_Select_s* sel,
char* objtype,
char* predef,
char* sort,
char* changed_since,
int incl_common_attrs,
int offset,
int count,
char* setreq,
char* setid,
char* contingent_itemidref);
Selection expression, see zxid_mk_dap_select().
Either "entry", or "_Subsciption". The former is used for searching and manipulating the normal attribute data while the latter is used for manipulating subscription objects. Specifying NULL selects "entry".
Predefined serverside operation identifier. This is server dependent, but you can think of it as a stored procedure. If you pass predef, it is common to leave sel and objtype as NULL and vice versa, i.e. you should pass NULL as predef unless you know your server to expect otherwise.
String specifying sorting of the result set. See ID-DAP specification for further details. N.B. Not all servers support sorting. Pass NULL if you do not need sorting.
LDAP date time string specifying that only entries that have changed since specified moment should be returned.
If 1 (true), "common" LDAP attributes such as modificationtime are included. If you do not need these attributes you can save the server some work and also some network transmission overhead by not requesting these attributes, i.e. pass 0 (false).
If search matches multiple entries, the zero based index of the first entry to return. Pass 0 to get the beginning of the result set.
Maximum number of entries to return in the response. 0 means return all. offset and count allow pagination through large result set. N.B. count is very different from sizelimit that you may specify in zxid_mk_dap_select(). The latter causes the actual backend search operation to abort or return partial result set if the result would be too large and is unsuitable for pagination.
Request creation of a result set snapshot for pagination. N.B. It is possible to paginate through large result set even without creating a snapshot, but the results may be inconsistent because the underlying data may change between queries that paginate through it. Creating a snapshot avoids this problem. Whether pagination with or without snapshot is cheaper depends on the backend implementation. setreq is specified on the first query that referes to the snapshot. The subsequent queries referring to the same snapshot will specify setid. The two are mutually exclusive: if setid is specified the setreq must be NULL.
If you are paginating through a result set snapshot created using setreq, then you must specify setid in subsequent queries that refer to same snapshot. When specifying setreq, you muse leave setid as NULL.
A query item can be made contingent on a test item, i.e. the query will only be made if the test succeeded. If you want this, you must pass the item ID of the test item here. Passing NULL means that no such dependency exists. N.B. The server side implementation of the tests may actually require a query to be made anyway.
struct zx_dap_Select_s* zxid_mk_dap_select(struct zxid_conf* cf,
char* dn,
char* filter,
char* attributes,
int deref_aliases,
int scope,
int sizelimit,
int timelimit,
int typesonly);
Distinguished or relative distinguished name. Since ID-DAP usually uses the identity conveyed using ID-WSF headers to determine the distinguished name, it is common to pass simply a NULL.
LDAP filter to apply. NULL if none.
List of attributes to return. NULL means return all attributes.
Boolean: whether the server should chase any "symlinks", i.e. an entry may appear at some location as an alias that is just a pointer to the real location of the entry. This is usually what you want so pass 1 (true).
The scope of the ID-DAP search.
Only what is pointed to by DN, e.g. one entry. The default.
Single level of directory right under DN.
Full subtree search under the DN.
Maximum number of entries to return. 0 means no limit. This is intended to stop the server from accidentally performing expensive queries. N.B. sizelimit is different from count, see zxid_mk_dap_query_item(), the latter is meant for pagination of a large result set without aborting it.
Maximum number of seconds to spend in the search. 0 means no limit.
If true, only attribute names are returned, without their values. This allows an existence test to be performed without passing the values over the network. Usually you want the values so you would pass 0 (false).
struct zx_dap_TestItem_s* zxid_mk_dap_test_item(struct zxid_conf* cf,
struct zx_dap_TestOp_s* tstop,
char* objtype,
char* predef);
See zxid_mk_dap_testop().
See objtype in zxid_mk_dap_query_item().
See predef in zxid_mk_dap_query_item().
struct zx_dap_TestOp_s* zxid_mk_dap_testop(struct zxid_conf* cf,
char* dn,
char* filter,
char* attributes,
int deref_aliases,
int scope,
int sizelimit,
int timelimit,
int typesonly);
See description of zxid_mk_dap_select(). For ID-DAP protocol the Select and TestOp are defined to be the same. However, this need not be the case for Data Services Template (DST) based services in general. Hence, the data types for Select and TestOp are different (although very similar) and two separate constructors are needed.
struct zx_dap_Subscription_s* zxid_mk_dap_subscription(struct zxid_conf* cf,
char* subsID,
char* itemidref,
struct zx_dap_ResultQuery_s* rq,
char* aggreg,
char* trig,
char* starts,
char* expires,
int incl_data,
char* admin_notif,
char* notify_ref);
Subscription ID
When subscribing to data described by a query item, create item, or modify item, the reference to the relevant item. NULL if no such item exists, in which case rq is usually specified.
Result query that identifies the data of interest for the subscription. See zxid_mk_dap_resquery(). Pass NULL if the data is identified otherwise, e.g. via itemidref.
Notification aggregation mode. Implementation dependent. Pass NULL. Notification aggregation is an optimization where some notification may be delayed a little so that it can be sent more optimally in same message with other notifications that may happen a little later. This functionality need not be supported by the backend implementations.
Implementation dependent notification triggers. Pass NULL.
Start date time of the subscription. NULL means subscription starts immediately.
End data time of the subscription. NULL means the subscription will not expire.
If 1 (true), the notifications resulting from the subscription will contain the changed data (push model). If 0 (false), the notification will just say that something changed, but interested party will need to perform a separate query to retrieve the data (pull model).
Administrative notification address. If NULL, the notify_ref will be used for administrative notifications as well.
Notification address.
struct zx_dap_ResultQuery_s* zxid_mk_dap_resquery(struct zxid_conf* cf,
struct zx_dap_Select_s* sel,
char* objtype,
char* predef,
char* sort,
int incl_common_attr,
char* changed_since,
char* contingent_itemidref);
See description of zxid_mk_dap_query_item().
HR-XML defines a XML document format that can be used for data interchange in the Human Resources world. The essence of HR-XML is to represent CV (Curriculum Vitae, a.k.a. Resume) in structured form.
At the moment (June 2007) HR-XML does not define any standard way to pass these documents around. In CV 2007 conference organized by EIfE-L in Paris, an idea was canvassed: use Liberty Data Service to exchange HR-XML documents. I tried to implement such service during the conference, but only got it working at the air port after the conference.
This service is a good example of how to apply ZXID to implement your own services.
Files
sg/hr-xml-sampo.sg - A slightly modified version of HR-XML schema sg/id-hrxml.sg - Liberty DST 2.1 based data service for HR-XML zxidhrxmlwsc.c - Web Services Client for HR-XML zxidhrxmlwsp.c - Web Services Provider for HR-XML
Running demo
Set up your /etc/hosts. At least you need sp1.zxidsp.org and you may also need your IdPs domain name (e.g. idp.symdemo.com).
Start your IdP and DS (not supplied with ZXID)
cd /opt/SYMfiam/std
conf/test-idp3/start.sh start log
Next you need to cause the id-hr-xml services to be registered in the discovery service. This depends on product.
Then you need to create an association for id-hr-xml service for some test user.
Start the web services client
mini_httpd -p 8443 -c 'zxid*' -S -E zxid.pem -l tmp/mini.stderr &
tail -f tmp/zxid.stderr&
Start the web services provider
mini_httpd -p 8444 -c 'zxid*' -S -E zxid.pem -l tmp/mini2.stderr &
tail -f tmp/zxid2.stderr&
Start browsing from
https://sp1.zxidsp.org:8443/zxidhrxmlwsc?o=E
Login using the test user that has the association
Paste
Click Query. This queries the WSP for the record we saved in previous step. You should see the record appear in the HR-XML Response field.
http://s-idp.liberty-iop.org:8881/N
Conor P. Cahill, of AOL and Intel fame, has developed and maintains a C++ library for ID-WSF 2.0 Web Service Client functionality for selected application protocols, including the ID-WSF 2.0 Discovery and some application protcols. Conor also provides a server side package that implements the corresponding WSP roles in Java. These libraries are valuable resources and come with extensive test suites - in fact, passing Conor's test suites has become the gold standard for validity and interoperability of any ID-WSF implmentations (this is not to detract from formal IOP events and the Liberty certification program, but passing Conor's test suite is a good predictor of getting certified).
Install Recipe
Conor's libraries have certain dependencies. Following is my best understanding
of how to get them installed.
mkdir conor cd conor tar xvf /t/LibertyIDWSFServices-v0.8.2.tgz cd .. mkdir conor-cli cd conor-cli/ tar xvf /t/LibertyClientToolkit-v1.0.1.tgz
Pat Patterson of Sun distributes a pure PHP module (not to be confused with Sun's OpenSSO open source effort, with which Pat has some contact) that implements some aspects of SAML 2.0. As of May 2007, his library provides functionality that, by and large, parallels that of the php_zxid module. A major advatage of his module is that it does not have C shared library dependency, but beware that he still depends on XML parsing and popular crypto libraries (openssl) to be available. These assumptions are not onerous, but you should be aware of them in case your system differs from main stream deployments.
Overall, Pat's PHP implementation, as of May 2007, is still lacking in metadata generation and loading (it does not implement Auto-CoT or Well Known Location) and has some rough edges around less frequently used parts of the SAML specification. No doubt matters will improve over the time.
Pat's library handles only SSO and not ID Web Services. It would be possible to extract the discovery bootstrap from SSO using his library after which you can use ZXID WSC API to actually call the services.
Sun Microsystems distributes an open source implementation of SAML 2.0. Their implementation is of primary interest as it provides a freely available IdP implementation (as of May 2007 IMNSHO the ZXID SP interface is superior to the OpenSSO SP - and since both implement an open standard, you can mix ZXID SP with OpenSSO IdP).
Thus, the ZXID to OpenSSO integration reduces to each one acting in its role using standard wire protocol - SAML 2.0.
The ZXID code generation methodology can be used to create interfaces to any XML document or protocol that can be described as a Schema Grammar (which includes any document that can be expressed as XML Schema - XSD). The general steps are
Convert .xsd file to .sg, or write the .sg directly. For conversion, you would typically use a command like
~/pd/xsd2sg.pl <foo.xsd >foo.sg
Tweak and rationalize the resulting .sg file. In ideal world any construct expressible as .xsd should be nicely representable, but in practise some work better than others, thus you can create a much nicer interface if you invest in some manual tweaking.
Note that the tweaked .sg still is able to represent the same document as the original .xsd described, though often the tweaking causes some relaxation.
Most common tweaks
If the .xsd is written so that the targeted namespace is also the default namespace, you should introduce a namespace prefix because this is needed during code generation to keep different C identifiers from clashing with each other. Ideally you should coordinate the namespace prefixes globally so that even two different projects will not clash.
Where the choice construct is used, indicated by pipey symbol (|) in the .sg file, you should refactor these into sequences of zero-or-one occurrence (?) instances of the alternatives of the choice. This is needed because for the foreseeable future xsd2sg.pl has a limitation in code generation feature. If the choice has maxOccurs="unbounded" you should use (*) instead.
xml:lang and other similar attributes may need to be factored open to be just of type %xs:string. This is a bug in xsd2sg.pl
"Connect" the schema to bigger framework. Usually this means adding your schema grammar to the ZX_SG variable in zxid/Makefile and supplying additional -r flags in ZX_ROOT variable. This allows your new schema to be visible at top level.
If your schema is meant to extend leafs or interior nodes of the parse tree, such as SOAP Body, you would edit the SOAP schema to accept your new protocol elements in the Body. Or that the generic SOAP header can accept your specific header schemata, or that the SAML attribute definitions accept your kind of attributes - whatever makes sense in your context.
Alternative to this is to create an entirely new monolithic encoder decoder, i.e. instead of extending the existing ZXID project to accommodate your new protocol, you just start a new project that uses the same methodology. You should see how the SAML protocol part is separated from the SAML metadata parsing and from the WSF parsing in the existing project.
Immediate goal: build a SAML 2.0 SP and ID-WSF 2.0 WSC
Goals of ZXID project include
SOAP 1.1 support (done)
SAML 2.0 compliance
SP role (done)
IdP role
Liberty ID-FF 1.2 support
SP
IdP
SAML 1.1
Liberty ID-WSF 1.1 support
Discovery bootstrap
Discovery WSC
ID-DAP WSC
ID-DAP WSP
Liberty ID-WSF 2.0 support
Discovery bootstrap (done)
Discovery WSC (done)
ID-DAP WSC (done)
ID-DAP WSP
Table 3:ZXID Platform Support
| Platform | Native | Cross Compile | Notes |
|---|---|---|---|
| Linux-ix86 | gcc-3.4.6 | n/a | Development platform |
| Solaris 8-sparc | gcc-3.4.6 | Linux gcc-3.4.6 | Fully functional |
| Windows 2000 | - | Linux gcc-3.4.6 | Poorly tested |
| xBSD/Unix | gcc-3.4.6 | n/a | C core tested, language bindings not tested |
Table 4:ZXID Feature and Language Support (version number indicates last testing)
| Feature | C | mod_perl | mod_php | Python | Java/Tomcat | Apache | Shell |
|---|---|---|---|---|---|---|---|
| Geo Location | Alpha | ||||||
| ID-MM7 | Alpha | ||||||
| ID-DAP | Beta | ||||||
| ID-HR-XML | Beta | ||||||
| Contact Book | Alpha | ||||||
| People Service | Alpha | ||||||
| Discovery | Yes | ||||||
| Web Services (ID-WSF) | Yes | ||||||
| SSO | 0.17 | 0.17 | 0.17 | Plan | 0.17 | Plan | 0.17 |
Table 5:ZXID Enabled Application Packages
| Application | Language | Notes |
|---|---|---|
| DokuWiki | PHP | Patch available, in process of submitting to DokuWiki authors |
Following directory layout is used by the project. Many of the specified directories are used by intermediate outputs that are not distributed in tarball releases, but may or may no be present in CVS checkouts.
zxid-0.xx | +-- Net The Net::SAML perl module (also mod_perl) +-- php PHP / mod_php integration +-- zxidjava The Java JNI interface to ZXID +-- servlet Apache Tomcat integration +-- c C code generated from the Schema Grammar descriptions +-- sg Schema Grammar (.sg) descriptions of protocols +-- xsd XML schema descriptions of protocols (not distributed) +-- tex Temporary files for document generation using PlainDoc (not distributed) +-- html HTML documentation generated using PlainDoc +-- review Publicly released announcements and documents (not distributed) +-- t Test scripts and expected test outputs `-- tmp Temporary files, such as actual test outputs
The Manifest file, which follows, explains each file in more detail.
# zxid/Manifest # $Id: Manifest,v 1.44 2008-09-17 18:19:20 sampo Exp $ # Packing list for distribution and explanation of files Manifest - This file. Describes contents of the distribution. Changes - Change log and revision history INSTALL.zxid - Quick installation instructions for the impatient README.zxid - How to build and operate ZXID, API documentation README.zxid-win32 - Windows build notes (preliminary Jan 2007) apache.pd - Apache specific configuration instructions mediawiki-zxid.pd - Documentation on MediaWiki integration LICENSE-2.0.txt - Apache License v2.0 ca.crt - Certification Authority certificate for zxid.pem zxid.pem - Certificate and provatekwy combo for testing (not secure) favicon.ico - A ZX/SP favicon for use in deno SPs gen-consts-from-gperf-output.pl - Used in build process gen-cot-links.pl - Handy tool for creating documentative symlinks in CoT directory pulverize.pl - A build tool for generating pulverized libraries for dead function elimination call-anal.pl - Call graph analysis tool (see make callgraph) # Handwritten code Makefile - Used to build ZXID (needs GNU make) BSDmakefile - Trigger gmake on BSD systems errmac.h - Error reporting and utility macros platform.h - Platform support kludges saml2.h - SAML related constants wsf.h - Liberty ID-WSF related constants zx.h - General data structures and prototypes used by generated code zxid.h - Specific data structures and prototypes for handwritten code zxidconf.h - Configuration parameters and default configuration of ZXID zxidnoswig.h - Prototypes that give indigestion to SWIG zxwsc.h - Specific data structures and prototypes for Web Services Client aux-templ.c - Code generation template for auxiliary functions dec-templ.c - Code generation template for decoders enc-templ.c - Code generation template for encoders ds-templ.c - Code generation template for DS script API getput-templ.c - Code generation template for accessor functions zxlog.c - Logging routines with encryption and signing zxlogview.c - Log viewing tool with decryption and sig verification zxsig.c - XML DSIG support zxcrypto.c - Cryptographical functions zxlib.c - Functions used to capture commonalities in generated code zxns.c - Namespace manipulation functions for generated code zxutil.c - Common library functions used by zx system zxidcgi.c - SP specific CGI parsing (see zxid.h) zxidconf.c - Configuration file and option parsing (see zxid.h) zxidses.c - SP session creation, parsing, and destruction (see zxid.h) zxiduser.c - Local user account management (see zxid.h) zxidecp.c - Enhanced Client Proxy check and functionality (see zxid.h) zxidcdc.c - Common Domain Cookie check (see zxid.h) zxidloc.c - Service Locator: compute from metadata and input the end point to use zxidlib.c - Common library functions for SSO (see zxid.h) zxidmeta.c - Metadata generation, parsing, and cache zxidcurl.c - Glue to libcurl zxidmk.c - Handwritten constructors for SSO zxidmni.c - NameID Management zxidslo.c - Single Logout and other management functions zxidsso.c - Single Sign-On functions zxida7n.c - Functions for querying assertions zxidepr.c - End Point Reference (EPR) and bootstrap handling zxidwsc.c - Handwritten ID-WSF Web Services Client engine zxidmkwsf.c - Handwritten constructors for WSF zxidhlowsf.c - Demonstration of calling ID-WSF services (DS and DAP) zxidxmltool.c - Testing tool for parsing XML zxbench.c - A benchmarking tool zxencdectest.c - An XML encoding and decoding testing tool zxidssofinalizetest.c - Test zxid_sso_finalize() # Full API demos zxid.c - Main ZXID SP program (a CGI script) zxid.pl - SAML 2.0 SP example written in perl zxid.php - SAML 2.0 SP example written in php zxid.java - SAML 2.0 SP example written in java (as CGI script) zxid-java.sh - Shell script for wrapping zxid.java with correct paths zxidwsctool.c - Command line Web Services Client, a tool for making ID-WSF calls # Simple and Hello World demos zxidsimp.c - Simple API main definition zxidhlo.c - Hello World SSO using simple API zxidsimple.c - Simple API helper program for shell scripts zxidhlo.sh - Hello World SSO as a shell script zxidhlo.php - Hello World SSO as a PHP script to run under mod_php zxidhlocgi.php - Hello World SSO as a PHP script to run as stand alone CGI script zxidhlo.pl - Hello World SSO as a PHP script zxidhlo-java.sh - Script to set Java environment zxidhlo.java - Hello World SSO using Java JNI servlet/WEB-INF/web.xml - Hello World servlet definition zxidhrxmlwsc.c - Example of ID-SIS HR-XML Web Services Client zxidhrxmlwsp.c - Example of ID-SIS HR-XML Web Services Provider zxidsp.c - A slightly more configurable use of simple API # Default Circle of Trust partner IdP's metadata default-cot/OKCy5mMaXMJUnKQ1wVJCcT00AA8 - auth-int.orange.fr default-cot/ZLIYSwzbSQdzIWHISwoWtdrx6JI - auth.orange.fr default-cot/_CBGcFVVbIEmt5oh3jUx4GEfHLM - idp.symdemo.com # Module generation facilities phpzxid.i - SWIG input file for php_zxid.so PHP extension pyzxid.i - SWIG input file for py_zxid.so Python extension rubyzxid.i - SWIG input file for ruby_zxid.so Ruby extension csharpzxid.i - SWIG input file for csharp_zxid.so C# extension javazxid.i - SWIG input file for libzxidjni.so Java JNI extension wsc.i - SWIG input file for Net::WSF::WSC perl module wsfraw.i - SWIG input file for Net::WSF::Raw perl module zxid.i - SWIG input file for Net::SAML perl module zxidmd.i - SWIG input file for Net::SAML::Metadata perl module zxidraw.i - SWIG input file for Net::SAML::Raw perl module # Schema grammar descriptions (used as input to code generation) sg/liberty-authentication-context-v2.0.sg sg/liberty-idff-protocols-schema-1.2-errata-v2.0.sg sg/liberty-idff-utility-v1.0.sg sg/liberty-idwsf-disco-svc-v1.2.sg sg/liberty-idwsf-disco-svc-v2.0.sg sg/liberty-idwsf-interaction-svc-v1.1.sg sg/liberty-idwsf-interaction-svc-v2.0.sg sg/liberty-idwsf-security-mechanisms-v1.2.sg sg/liberty-idwsf-security-mechanisms-v2.0.sg sg/liberty-idwsf-soap-binding-v1.2.sg sg/liberty-idwsf-soap-binding-v2.0.sg sg/liberty-idwsf-soap-binding.sg - Framework SOAP header sg/liberty-idwsf-utility-1.0-errata-v1.0.sg sg/liberty-idwsf-utility-v1.1.sg sg/liberty-idwsf-utility-v2.0.sg sg/liberty-metadata-v2.0.sg sg/liberty-utility-v2.0.sg sg/oasis-sstc-saml-schema-assertion-1.1.sg sg/oasis-sstc-saml-schema-protocol-1.1.sg sg/saml-schema-assertion-2.0.sg sg/saml-schema-metadata-2.0.sg sg/saml-schema-protocol-2.0.sg sg/saml-schema-ecp-2.0.sg sg/liberty-paos-v2.0.sg sg/ws-addr-1.0.sg sg/wsf-soap11.sg - Mega SOAP parser for SAML and ID-WSF messages sg/wss-secext-1.0.sg sg/wss-util-1.0.sg sg/xenc-schema.sg sg/xmldsig-core.sg sg/ec.sg - IncludedNamespaces from Exclusive Canonicalization sg/xml.sg sg/xsi.sg sg/xs.sg sg/id-dap.sg - ID Directory Access Protocol sg/lib-id-sis-cb-proto.sg - Contact Book Protocol sg/lib-id-sis-cb-cdm.sg - Contact Book Conceptual Data Model sg/liberty-id-sis-gl-v1.0-14.sg - Geo Location Service sg/id-mm7-R6-1-4.sg sg/liberty-idwsf-dst-v2.0.sg - DST 2.0 sg/liberty-idwsf-dst-dt-v2.0.sg - DST 2.0 data types sg/liberty-idwsf-subs-ref-v1.0.sg sg/liberty-idwsf-subs-v1.0.sg sg/liberty-idwsf-dst-v2.1.sg sg/liberty-idwsf-idmapping-svc-v2.0.sg sg/liberty-idwsf-people-service-v1.0.sg sg/liberty-idwsf-authn-svc-v2.0.sg sg/access_control-xacml-2.0-context-schema-os.sg sg/access_control-xacml-2.0-policy-schema-os.sg sg/access_control-xacml-2.0-saml-assertion-schema-os.sg sg/access_control-xacml-2.0-saml-protocol-schema-os.sg sg/ws-trust-1.3.sg sg/ws-policy.sg sg/ws-secureconversation-1.3.sg # Schema generated C code (see also Makefile if you add files) c/license.c - Generated file: License string c/zxidvers.h - Generated file: version string c/zx-attrs.c - Generated: Mapping of a string to attribute token c/zx-aux.c - Generated from aux-templ.c and various .sg files c/zx-const.h - Generated: Token value constants c/zx-data.h - Generated: Data structures reflecting schemata (.sg files). Root object. c/zx-dec.c - Generated from dec-templ.c and various .sg files. The root decoder. c/zx-elems.c - Generated: Mapping of a string to element token c/zx-enc.c - Generated from enc-templ.c and various .sg files. The root encoder. c/zx-getput.c - Generated from getput-templ.c and various .sg files c/zx-ns.c - Generated: initializations of namespace tables c/zx-ns.h - Generated: namespace constant and macro definitions c/zx-a-data.h - Generated: Web Services Addressing data structures c/zx-a-aux.c - Generated from aux-templ.c: WS-Addr aux functions c/zx-a-dec.c - Generated from dec-templ.c: WS-Addr decoders c/zx-a-enc.c - Generated from enc-templ.c: WS-Addr encoders c/zx-a-getput.c - Generated from getput-templ.c c/zx-ac-data.h; c/zx-ac-aux.c; c/zx-ac-dec.c; c/zx-ac-enc.c; c/zx-ac-getput.c c/zx-b-data.h; c/zx-b-aux.c; c/zx-b-dec.c; c/zx-b-enc.c; c/zx-b-getput.c c/zx-b12-data.h; c/zx-b12-aux.c; c/zx-b12-dec.c; c/zx-b12-enc.c; c/zx-b12-getput.c c/zx-di-data.h; c/zx-di-aux.c; c/zx-di-dec.c; c/zx-di-enc.c; c/zx-di-getput.c c/zx-di12-data.h; c/zx-di12-aux.c; c/zx-di12-dec.c; c/zx-di12-enc.c; c/zx-di12-getput.c c/zx-ds-data.h; c/zx-ds-aux.c; c/zx-ds-dec.c; c/zx-ds-enc.c; c/zx-ds-getput.c c/zx-e-data.h; c/zx-e-aux.c; c/zx-e-dec.c; c/zx-e-enc.c; c/zx-e-getput.c c/zx-ff12-data.h; c/zx-ff12-aux.c; c/zx-ff12-dec.c; c/zx-ff12-enc.c; c/zx-ff12-getput.c c/zx-is-data.h; c/zx-is-aux.c; c/zx-is-dec.c; c/zx-is-enc.c; c/zx-is-getput.c c/zx-is12-data.h; c/zx-is12-aux.c; c/zx-is12-dec.c; c/zx-is12-enc.c; c/zx-is12-getput.c c/zx-lu-data.h; c/zx-lu-aux.c; c/zx-lu-dec.c; c/zx-lu-enc.c; c/zx-lu-getput.c c/zx-m20-data.h; c/zx-m20-aux.c; c/zx-m20-dec.c; c/zx-m20-enc.c; c/zx-m20-getput.c c/zx-md-data.h; c/zx-md-aux.c; c/zx-md-dec.c; c/zx-md-enc.c; c/zx-md-getput.c c/zx-ecp-data.h; c/zx-ecp-aux.c; c/zx-ecp-dec.c; c/zx-ecp-enc.c; c/zx-ecp-getput.c c/zx-paos-data.h; c/zx-paos-aux.c; c/zx-paos-dec.c; c/zx-paos-enc.c; c/zx-paos-getput.c c/zx-sa-data.h; c/zx-sa-aux.c; c/zx-sa-dec.c; c/zx-sa-enc.c; c/zx-sa-getput.c c/zx-sa11-data.h; c/zx-sa11-aux.c; c/zx-sa11-dec.c; c/zx-sa11-enc.c; c/zx-sa11-getput.c c/zx-sbf-data.h; c/zx-sbf-aux.c; c/zx-sbf-dec.c; c/zx-sbf-enc.c; c/zx-sbf-getput.c c/zx-sec-data.h; c/zx-sec-aux.c; c/zx-sec-dec.c; c/zx-sec-enc.c; c/zx-sec-getput.c c/zx-sec12-data.h; c/zx-sec12-aux.c; c/zx-sec12-dec.c; c/zx-sec12-enc.c; c/zx-sec12-getput.c c/zx-sp-data.h; c/zx-sp-aux.c; c/zx-sp-dec.c; c/zx-sp-enc.c; c/zx-sp-getput.c c/zx-sp11-data.h; c/zx-sp11-aux.c; c/zx-sp11-dec.c; c/zx-sp11-enc.c; c/zx-sp11-getput.c c/zx-wsse-data.h; c/zx-wsse-aux.c; c/zx-wsse-dec.c; c/zx-wsse-enc.c; c/zx-wsse-getput.c c/zx-wsu-data.h; c/zx-wsu-aux.c; c/zx-wsu-dec.c; c/zx-wsu-enc.c; c/zx-wsu-getput.c c/zx-xenc-data.h; c/zx-xenc-aux.c; c/zx-xenc-dec.c; c/zx-xenc-enc.c; c/zx-xenc-getput.c c/zx-exca-data.h; c/zx-exca-aux.c; c/zx-exca-dec.c; c/zx-exca-enc.c; c/zx-exca-getput.c c/zx-xsi-data.h; c/zx-xsi-aux.c; c/zx-xsi-dec.c; c/zx-xsi-enc.c; c/zx-xsi-getput.c c/zx-xs-data.h; c/zx-xs-aux.c; c/zx-xs-dec.c; c/zx-xs-enc.c; c/zx-xs-getput.c c/zx-xml-data.h; c/zx-xml-aux.c; c/zx-xml-dec.c; c/zx-xml-enc.c; c/zx-xml-getput.c c/zx-dap-data.h; c/zx-dap-aux.c; c/zx-dap-dec.c; c/zx-dap-enc.c; c/zx-dap-getput.c c/zx-ps-data.h; c/zx-ps-aux.c; c/zx-ps-dec.c; c/zx-ps-enc.c; c/zx-ps-getput.c c/zx-im-data.h; c/zx-im-aux.c; c/zx-im-dec.c; c/zx-im-enc.c; c/zx-im-getput.c c/zx-as-data.h; c/zx-as-aux.c; c/zx-as-dec.c; c/zx-as-enc.c; c/zx-as-getput.c c/zx-subs-data.h; c/zx-subs-aux.c; c/zx-subs-dec.c; c/zx-subs-enc.c; c/zx-subs-getput.c c/zx-dst-data.h; c/zx-dst-aux.c; c/zx-dst-dec.c; c/zx-dst-enc.c; c/zx-dst-getput.c c/zx-cb-data.h; c/zx-cb-aux.c; c/zx-cb-dec.c; c/zx-cb-enc.c; c/zx-cb-getput.c c/zx-cdm-data.h; c/zx-cdm-aux.c; c/zx-cdm-dec.c; c/zx-cdm-enc.c; c/zx-cdm-getput.c c/zx-gl-data.h; c/zx-gl-aux.c; c/zx-gl-dec.c; c/zx-gl-enc.c; c/zx-gl-getput.c c/zx-mm7-data.h; c/zx-mm7-aux.c; c/zx-mm7-dec.c; c/zx-mm7-enc.c; c/zx-mm7-getput.c c/zx-xa-data.h; c/zx-xa-aux.c; c/zx-xa-dec.c; c/zx-xa-enc.c; c/zx-xa-getput.c c/zx-xac-data.h; c/zx-xac-aux.c; c/zx-xac-dec.c; c/zx-xac-enc.c; c/zx-xac-getput.c c/zx-xasa-data.h; c/zx-xasa-aux.c; c/zx-xasa-dec.c; c/zx-xasa-enc.c; c/zx-xasa-getput.c c/zx-xasp-data.h; c/zx-xasp-aux.c; c/zx-xasp-dec.c; c/zx-xasp-enc.c; c/zx-xasp-getput.c c/zx-wst-data.h; c/zx-wst-aux.c; c/zx-wst-dec.c; c/zx-wst-enc.c; c/zx-wst-getput.c c/zx-wsp-data.h; c/zx-wsp-aux.c; c/zx-wsp-dec.c; c/zx-wsp-enc.c; c/zx-wsp-getput.c c/zx-wsc-data.h; c/zx-wsc-aux.c; c/zx-wsc-dec.c; c/zx-wsc-enc.c; c/zx-wsc-getput.c # Advanced Client c/zx-dp-data.h; c/zx-dp-aux.c; c/zx-dp-dec.c; c/zx-dp-enc.c; c/zx-dp-getput.c c/zx-pmm-data.h; c/zx-pmm-aux.c; c/zx-pmm-dec.c; c/zx-pmm-enc.c; c/zx-pmm-getput.c c/zx-prov-data.h; c/zx-prov-aux.c; c/zx-prov-dec.c; c/zx-prov-enc.c; c/zx-prov-getput.c c/zx-idp-data.h; c/zx-idp-aux.c; c/zx-idp-dec.c; c/zx-idp-enc.c; c/zx-idp-getput.c c/zx-shps-data.h; c/zx-shps-aux.c; c/zx-shps-dec.c; c/zx-shps-enc.c; c/zx-shps-getput.c # Unofficial stuff c/zx-hrxml-data.h; c/zx-hrxml-aux.c; c/zx-hrxml-dec.c; c/zx-hrxml-enc.c; c/zx-hrxml-getput.c c/zx-idhrxml-data.h; c/zx-idhrxml-aux.c; c/zx-idhrxml-dec.c; c/zx-idhrxml-enc.c; c/zx-idhrxml-getput.c c/zx-demomed-data.h; c/zx-demomed-aux.c; c/zx-demomed-dec.c; c/zx-demomed-enc.c; c/zx-demomed-getput.c # Expected output for various test cases t/authnreq.xml t/se-req.xml t/se-req2.xml t/se-resp.xml t/se-artif-resp.xml - Example response to artifact resolution. Shows SSO assertion. t/sso-w-bootstraps.xml - Example response to artifact resolution. Shows SSO assertion w/bootstraps t/x509.xml - Example of ID-WSF SOAP call using x509 sec mech t/bin-bearer.xml - Example of ID-WSF SOAP call using bearer token (binary) sec mech t/saml-bearer.xml - Example of ID-WSF SOAP call using bearer token (SAML2) sec mech # Apache authentication module mod_auth_saml.c - Apache auth module to SAML protect web pages protected/content.txt - Test content for mod_auth_saml protected/saml - Test content for mod_auth_saml protected/orange.cgi - Demonstration of using Orange Personal APIs # Net::SAML module (zxid.i) Net/README.zxid-perl Net/Makefile.PL - How to build the module Net/SAML.pod - Bare bones documentation Net/SAML.pm - Generated with SWIG from zxid.i and headers Net/SAML_wrap.c - Generated with SWIG from zxid.i and headers Net/test.pl - Unit tests # php_zxid.so PHP extension (phpzxid.i) php/README.zxid-php php/php_zxid.h - Generated php/zxid.php - Generated php/zxid_wrap.c - Generated # py_zxid.so Python extension (pyzxid.i) py/README.zxid-py py/zxid.py - Generated py/zxid_wrap.c - Generated # ruby_zxid.so Ruby extension (rubyzxid.i) ruby/README.zxid-ruby #ruby/zxid.ruby - Generated ruby/zxid_wrap.c - Generated # csharp_zxid.so C# extension (csharpzxid.i) csharp/README.zxid-csharp csharp/zxid.cs - Generated csharp/zxid_wrap.c - Generated csharp/SWIGTYPE_p_X509.cs csharp/SWIGTYPE_p_f_p_void__void.cs csharp/SWIGTYPE_p_f_p_void_size_t__p_void.cs csharp/SWIGTYPE_p_f_size_t__p_void.cs csharp/SWIGTYPE_p_int.cs csharp/SWIGTYPE_p_p_char.cs csharp/SWIGTYPE_p_p_void.cs csharp/SWIGTYPE_p_p_zx_ns_s.cs csharp/SWIGTYPE_p_p_zx_xenc_EncryptedKey_s.cs csharp/SWIGTYPE_p_time_t.cs csharp/SWIGTYPE_p_timeval.cs csharp/SWIGTYPE_p_unsigned_char.cs csharp/SWIGTYPE_p_void.cs csharp/SWIGTYPE_p_zx_a_Address_s.cs csharp/SWIGTYPE_p_zx_a_EndpointReference_s.cs csharp/SWIGTYPE_p_zx_any_attr_s.cs csharp/SWIGTYPE_p_zx_any_elem_s.cs csharp/SWIGTYPE_p_zx_ctx.cs csharp/SWIGTYPE_p_zx_dap_QueryItem_s.cs csharp/SWIGTYPE_p_zx_dap_Query_s.cs csharp/SWIGTYPE_p_zx_dap_ResultQuery_s.cs csharp/SWIGTYPE_p_zx_dap_Select_s.cs csharp/SWIGTYPE_p_zx_dap_Subscription_s.cs csharp/SWIGTYPE_p_zx_dap_TestItem_s.cs csharp/SWIGTYPE_p_zx_dap_TestOp_s.cs csharp/SWIGTYPE_p_zx_di_Query_s.cs csharp/SWIGTYPE_p_zx_ds_KeyInfo_s.cs csharp/SWIGTYPE_p_zx_ds_Reference_s.cs csharp/SWIGTYPE_p_zx_ds_Signature_s.cs csharp/SWIGTYPE_p_zx_e_Body_s.cs csharp/SWIGTYPE_p_zx_e_Envelope_s.cs csharp/SWIGTYPE_p_zx_e_Header_s.cs csharp/SWIGTYPE_p_zx_elem_s.cs csharp/SWIGTYPE_p_zx_ff12_Assertion_s.cs csharp/SWIGTYPE_p_zx_md_AssertionConsumerService_s.cs csharp/SWIGTYPE_p_zx_md_EntityDescriptor_s.cs csharp/SWIGTYPE_p_zx_md_KeyDescriptor_s.cs csharp/SWIGTYPE_p_zx_md_ManageNameIDService_s.cs csharp/SWIGTYPE_p_zx_md_SPSSODescriptor_s.cs csharp/SWIGTYPE_p_zx_md_SingleLogoutService_s.cs csharp/SWIGTYPE_p_zx_node_s.cs csharp/SWIGTYPE_p_zx_ns_s.cs csharp/SWIGTYPE_p_zx_root_s.cs csharp/SWIGTYPE_p_zx_sa11_Assertion_s.cs csharp/SWIGTYPE_p_zx_sa_Assertion_s.cs csharp/SWIGTYPE_p_zx_sa_Attribute_s.cs csharp/SWIGTYPE_p_zx_sa_EncryptedID_s.cs csharp/SWIGTYPE_p_zx_sa_Issuer_s.cs csharp/SWIGTYPE_p_zx_sa_NameID_s.cs csharp/SWIGTYPE_p_zx_sp_ArtifactResolve_s.cs csharp/SWIGTYPE_p_zx_sp_AuthnRequest_s.cs csharp/SWIGTYPE_p_zx_sp_LogoutRequest_s.cs csharp/SWIGTYPE_p_zx_sp_LogoutResponse_s.cs csharp/SWIGTYPE_p_zx_sp_ManageNameIDRequest_s.cs csharp/SWIGTYPE_p_zx_sp_ManageNameIDResponse_s.cs csharp/SWIGTYPE_p_zx_sp_NewEncryptedID_s.cs csharp/SWIGTYPE_p_zx_sp_Status_s.cs csharp/SWIGTYPE_p_zx_str.cs csharp/SWIGTYPE_p_zx_tok.cs csharp/SWIGTYPE_p_zx_xenc_EncryptedData_s.cs csharp/SWIGTYPE_p_zx_xenc_EncryptedKey_s.cs csharp/SWIGTYPE_p_zxid_cgi.cs csharp/SWIGTYPE_p_zxid_conf.cs csharp/SWIGTYPE_p_zxid_curl_ctx.cs csharp/SWIGTYPE_p_zxid_entity.cs csharp/SWIGTYPE_p_zxid_ses.cs csharp/SWIGTYPE_p_zxsig_ref.cs csharp/zxidPINVOKE.cs # libzxidjni.so Java JNI extension (javazxid.i) zxidjava/README.zxid-java zxidjava/zxid_wrap.c zxidjava/SWIGTYPE_p_X509.java zxidjava/SWIGTYPE_p_f_p_void__void.java zxidjava/SWIGTYPE_p_f_p_void_size_t__p_void.java zxidjava/SWIGTYPE_p_f_size_t__p_void.java zxidjava/SWIGTYPE_p_int.java zxidjava/SWIGTYPE_p_p_char.java zxidjava/SWIGTYPE_p_p_void.java zxidjava/SWIGTYPE_p_p_zx_ns_s.java zxidjava/SWIGTYPE_p_p_zx_xenc_EncryptedKey_s.java zxidjava/SWIGTYPE_p_time_t.java zxidjava/SWIGTYPE_p_timeval.java zxidjava/SWIGTYPE_p_unsigned_char.java zxidjava/SWIGTYPE_p_void.java zxidjava/SWIGTYPE_p_zx_a_Address_s.java zxidjava/SWIGTYPE_p_zx_a_EndpointReference_s.java zxidjava/SWIGTYPE_p_zx_dap_QueryItem_s.java zxidjava/SWIGTYPE_p_zx_dap_Query_s.java zxidjava/SWIGTYPE_p_zx_dap_ResultQuery_s.java zxidjava/SWIGTYPE_p_zx_dap_Select_s.java zxidjava/SWIGTYPE_p_zx_dap_Subscription_s.java zxidjava/SWIGTYPE_p_zx_dap_TestItem_s.java zxidjava/SWIGTYPE_p_zx_dap_TestOp_s.java zxidjava/SWIGTYPE_p_zx_di_Query_s.java zxidjava/SWIGTYPE_p_zx_ds_KeyInfo_s.java zxidjava/SWIGTYPE_p_zx_ds_Reference_s.java zxidjava/SWIGTYPE_p_zx_ds_Signature_s.java zxidjava/SWIGTYPE_p_zx_e_Body_s.java zxidjava/SWIGTYPE_p_zx_e_Envelope_s.java zxidjava/SWIGTYPE_p_zx_e_Header_s.java zxidjava/SWIGTYPE_p_zx_ff12_Assertion_s.java zxidjava/SWIGTYPE_p_zx_md_AssertionConsumerService_s.java zxidjava/SWIGTYPE_p_zx_md_EntityDescriptor_s.java zxidjava/SWIGTYPE_p_zx_md_KeyDescriptor_s.java zxidjava/SWIGTYPE_p_zx_md_ManageNameIDService_s.java zxidjava/SWIGTYPE_p_zx_md_SPSSODescriptor_s.java zxidjava/SWIGTYPE_p_zx_md_SingleLogoutService_s.java zxidjava/SWIGTYPE_p_zx_root_s.java zxidjava/SWIGTYPE_p_zx_sa11_Assertion_s.java zxidjava/SWIGTYPE_p_zx_sa_Assertion_s.java zxidjava/SWIGTYPE_p_zx_sa_Attribute_s.java zxidjava/SWIGTYPE_p_zx_sa_EncryptedID_s.java zxidjava/SWIGTYPE_p_zx_sa_Issuer_s.java zxidjava/SWIGTYPE_p_zx_sa_NameID_s.java zxidjava/SWIGTYPE_p_zx_sp_ArtifactResolve_s.java zxidjava/SWIGTYPE_p_zx_sp_AuthnRequest_s.java zxidjava/SWIGTYPE_p_zx_sp_LogoutRequest_s.java zxidjava/SWIGTYPE_p_zx_sp_LogoutResponse_s.java zxidjava/SWIGTYPE_p_zx_sp_ManageNameIDRequest_s.java zxidjava/SWIGTYPE_p_zx_sp_ManageNameIDResponse_s.java zxidjava/SWIGTYPE_p_zx_sp_NewEncryptedID_s.java zxidjava/SWIGTYPE_p_zx_sp_Status_s.java zxidjava/SWIGTYPE_p_zx_xenc_EncryptedData_s.java zxidjava/SWIGTYPE_p_zx_xenc_EncryptedKey_s.java zxidjava/zx_any_attr_s.java zxidjava/zx_any_elem_s.java zxidjava/zx_ctx.java zxidjava/zx_elem_s.java zxidjava/zx_node_s.java zxidjava/zx_ns_s.java zxidjava/zx_str.java zxidjava/zx_tok.java zxidjava/zxid_cgi.java zxidjava/zxid_conf.java zxidjava/zxid_curl_ctx.java zxidjava/zxid_entity.java zxidjava/zxid_ses.java zxidjava/zxidjni.java zxidjava/zxidjniConstants.java zxidjava/zxidjniJNI.java zxidjava/zxsig_ref.java # Precheck precheck/chk-zlib.c precheck/chk-openssl.c precheck/chk-curl.c precheck/chk-apache.c #EOF
The protocol encoders and decoders are generated automatically from the schema grammar (.sg) descriptions. This ensures accurate protocol implementation. While the output is strictly schema driven and correct, the decoders have some provisions to accept some deviations from strict spec (e.g. out of order elements are tolerated). However, one should note that XMLDSIG does not tolerate very much deviation, thus even if decoder accepts a slightly illformed message, it is likely to fail in signature verification.
There are three outputs from generation
Data structures describing the data (xx.h)
Encoder that linearizes the data structure to wire protocol (xx-enc.c)
Decoder that converts wire protocol byte stream to a data structure (xx-dec.c)
ZXID uses consistently the same namespace prefixes throughout the project. The generated encoders and decoders support following schemata
Table 6:ZXID Namespace Convention
| Prefix | URI | Description |
|---|---|---|
| sa | urn:oasis:names:tc:SAML:2.0:assertion | SAML 2.0 |
| sp | urn:oasis:names:tc:SAML:2.0:protocol | |
| md | urn:oasis:names:tc:SAML:2.0:metadata | |
| ecp | urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp | |
| paos | urn:liberty:paos:2006-08 | |
| sa11 | urn:oasis:names:tc:SAML:1.0:assertion | SAML 1.1 |
| sp11 | urn:oasis:names:tc:SAML:1.0:protocol | |
| ff12 | urn:liberty:iff:2003-08 | ID-FF 1.2 |
| m20 | urn:liberty:metadata:2004-12 | v2.0 (almost same as 1.2) |
| ac | urn:liberty:ac:2004-12 | v2.0 (almost same as 1.2) |
| b12 | urn:liberty:sb:2003-08 | ID-WSF 1.1 SOAP Binding |
| sec12 | urn:liberty:sec:2003-08 | ID-WSF 1.1 Security Mechanisms |
| di12 | urn:liberty:disco:2003-08 | ID-WSF 1.1 Discovery Service |
| is12 | urn:liberty:is:2003-08 | ID-WSF 1.1 Interaction Service |
| lu | urn:liberty:util:2006-08 | ID-WSF 2.0 Utility Schema |
| sbf | urn:liberty:sb | Framework header |
| b | urn:liberty:sb:2006-08 | ID-WSF 2.0 SOAP Binding |
| sec | urn:liberty:security:2006-08 | ID-WSF 2.0 Security Mechanisms |
| di | urn:liberty:disco:2006-08 | ID-WSF 2.0 Discovery Service |
| is | urn:liberty:is:2006-08 | ID-WSF 2.0 Interaction Service |
| dap | urn:liberty:id-sis-dap:2006-08:dst-2.1 | ID Directory Access Protocol |
| dst | urn:liberty:dst:2006-08 | Data Services Template 2.1 |
| subs | urn:liberty:ssos:2006-08 | Subscription and Notification |
| ps | urn:liberty:ps:2006-08 | People Service |
| im | urn:liberty:ims:2006-08 | Identity Mapping svc (aka Token Map) |
| as | urn:liberty:sa:2006-08 | ID-WSF 2.0 Authentication Service |
| cb | urn:liberty:id-sis-cb:2004-10 | Contact Book Protocol (DST 2.0 based) |
| cdm | urn:liberty:cb:conceptual-data-model:2004-10 | Contact Book Common Data Model |
| gl | urn:liberty:id-sis-gl:2005-07 | Geolocation Service |
| mm7 | http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-4 | ID-MM7 (ID-SIS-CSM) |
| dp | urn:liberty:dp:2006-12 | ID-WSF 2.0 Design Patterns |
| idp | urn:liberty:idp:2006-12 | ID-WSF 2.0 IdP as web svc |
| pmm | urn:liberty:pmm:2006-12 | ID-WSF 2.0 Prov Mod Mgr |
| prov | urn:liberty:prov:2006-12 | ID-WSF 2.0 TM Provisioning |
| shps | urn:liberty:shps:2006-12 | ID-WSF 2.0 Svc Handling and Proxying |
| e | http://schemas.xmlsoap.org/soap/envelope/ | SOAP 1.1, with SAML and WSF |
| xa | urn:oasis:names:tc:xacml:2.0:policy:schema:os | XACML 2.0 |
| xac | urn:oasis:names:tc:xacml:2.0:context:schema:os | |
| xasp | urn:oasis:xacml:2.0:saml:protocol:schema:os | |
| xasa | urn:oasis:xacml:2.0:saml:assertion:schema:os | |
| wst | http://docs.oasis-open.org/ws-sx/ws-trust/200512/ | WS-Trust 1.3 CD-01 |
| wsp | http://schemas.xmlsoap.org/ws/2004/09/policy | *** Newer version? http://www.w3.org/ns/ws-policy/ |
| wsc | http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512 | WS-Secure Conversation CD-01 |
| ds | http://www.w3.org/2000/09/xmldsig# | XML Signatures |
| xenc | http://www.w3.org/2001/04/xmlenc# | XML Encryption |
| exca | http://www.w3.org/2001/10/xml-exc-c14n# | Exclusive Canonicalization |
| a | http://www.w3.org/2005/08/addressing | WSA 1.0 |
| wsse | http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd | WS Security SecExt 1.0 |
| wsu | http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd | WS Security Utility 1.0 |
| xml | http://www.w3.org/XML/1998/namespace | http://www.w3.org/2001/xml.xsd |
| xsi | http://www.w3.org/2001/XMLSchema-instance | |
| xs | http://www.w3.org/2001/XMLSchema | Namespace only, no code |
| igf0 urn:LibertyAlliance:igf:0.3:core Early draft 01, WIP | carml0 urn:LibertyAlliance:igf:0.3:carml Early draft 03, WIP |
Main work horse of code generation is xsd2sg.pl, which serves multiple purposes
Build hashes of all declarations in .sg input. Each hash element consists of array of elements and attributes, as well as groups and attribute groups. The type of array element sis determined from prefix, per .sg rules.
Expand groups and attribute groups
Evaluate each element wrt its type and generate
C data structures
Decoder grammar
Token descriptions for perfect hash and lexical analyzer
Encoder C code
The code to build hashes is interwoven in the code that generates .xsd from .sg. The rest of the generation happens in a function called generate().
Typical command line (to generate SAML 2.0 protocol engine)
~/plaindoc/xsd2sg.pl -d -gen saml2 -p zx_ \
-r saml:Assertion -r se:Envelope \
-S \
sg/saml-schema-assertion-2.0.sg \
sg/saml-schema-protocol-2.0.sg \
sg/xmldsig-core.sg \
sg/xenc-schema.sg \
sg/soap11.sg \
>/dev/null
To generate SAML 2.0 Metadata engine you would issue
~/plaindoc/xsd2sg.pl -d -gen saml2md -p zx_ \
-r md:EntityDescriptor -r md:EntitiesDescriptor \
-S \
sg/saml-schema-assertion-2.0.sg \
sg/saml-schema-metadata-2.0.sg \
sg/xmldsig-core.sg \
sg/xenc-schema.sg \
>/dev/null
While C code generation is the main output, and this can always be converted to other languages using SWIG, sometimes a more natural language interface can be built by directly generating it.
We plan to enhance the code generation to do something like this. At least direct hash-of-hashes-of-arrays-of-hashes type data-structure generation for benefit of some scripting languages is planned.
*** warning: not checked lately, may be wrong!
Table 7:ZXID SP URLs
| URL | Description |
|---|---|
| /zxid | Same as o=M. Main convenience entry point |
| /zxid?o=M | SSO with CDC; or management if already logged in |
| /zxid?o=C | Common Domain Cookie (CDC) reader, usually under common domain host name. |
| /zxid?o=E | SSO after CDC read; or management if already logged in. |
| /zxid?o=P | HTTP POST end point. Used for forms and last part of POST profile SSO. |
| /zxid?o=Q | HTTP binding (POST or redirect) request end point (e.g. SLO, MNI). |
| /zxid?o=S | SOAP end point (HTTP POST) |
| /zxid?o=B | Get SP metadata (or combined SP and IdP metadata if proxying). |
*** add description of CGI fields
*** TBD - This chapter should be elaborated to be a certificate tutorial with following contents:
Intro to certs and private keys
Generating self signed cert
Generating certificate signing request and using it to obtain commercially issued cert
Installing root certs so you can recognize other people's certs
Client TLS considerations
For the time being, the short answer is that ZXID uses OpenSSL and PEM format certificates. You can use same techniques as you would use for Apache / mod_ssl for acquiring certificates.
You should NEVER password protect your private key. There will not be any opportunity to supply the password. You should instead protect your private key using Unix filesystem permissions. See OpenSSL.org or modssl.org FAQs for further information, including how to remove a password if you accidentally enabled it.
ZXID test suite is still in tatters. Some things that should be tested
Will generated HTTP redirect sig validate at IdP?
Does IdP issued A7N validate?
Validation of EncryptedAssertion?
Will generated SOAP binding sig validate at IdP?
Does IdP issued SOAP sig validate?
Metadata related
IBM metadata (can we parse)
Sun metadata (can we parse)
XML related
Fully qualified XML parses?
Unknown ns prefix that refers to known namespace URI
Known ns prefix, referring to wrong URI
Known prefix refers to aliased URI
Use of default namespaces working?
Unknown prefix and URI as long as it is never used
Unknown prefix and URI, used
Known NS (prefix or URI), unknown element
Copyright (c) 2006-2008 Symlabs (symlabs@symlabs.com), All Rights Reserved. Author: Sampo Kellomäki (sampo@iki.fi)
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
While the source distribution of ZXID does not contain SSLeay or OpenSSL code, if you use this code you will use OpenSSL library. Please give Eric Young and OpenSSL team credit (as required by their licenses).
Binary distribution of this product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/). See LICENSE.openssl for further information.
Binary distribution of this product includes cryptographic software written by Eric Young (eay@cryptsoft.com). Binary distribution of this product includes software written by Tim Hudson (tjh@cryptsoft.com). See LICENSE.ssleay for further information.
And remember, you, and nobody else but you, are responsible for auditing ZXID and OpenSSL library for security problems, back-doors, and general suitability for your application.
ZXID strives to maintain IPR hygiene and avoid both non-free and GPL license contamination. All the dependency libraries have BSD style licenses
OpenSSL under BSDish (with "advertising" clause)
libcurl under BSDish
zlib under BSDish
libc available as part of the operating system
Please see each library package for the exact details of their licenses.
ZXID is based on open SAML and Liberty specifications. The parties that have developed these specifications, including Symlabs, have made Royalty Free (RF) licensing commitment. Please ask OASIS and Liberty Alliance for the specifics of their IPR policies and IPR disclosures.
Some protocols, such as WS-Trust and WS-Federation enjoy Microsoft's
pledge
that they will
not sue you even if you implement these specifications. You should
evaluate yourself whether this is good enough for your situation.
If you need the author or Symlabs to further disclaim IPR interest or make warranties of non-infringement, such declarations are available for a fee. Please contact sales@symlabs.com
Legal queries and clarifications will be answered at then-current Symlabs Professional Services rate, please contact sales@symlabs.com.
ZXID does NOT have a configure script. It ships with a notion of "standard" locations for the three dependency libraries, but if these libraries are not where it expects to find them, then typically you see (n.b. lines were folded for presentation):
make
If you get compilation errors, try: make help
gcc -g -fpic -fmessage-length=0 -Wno-unused-label -Wno-unknown-pragmas
-fno-strict-aliasing -D_REENTRANT -DDEBUG -DUSE_CURL -DUSE_OPENSSL
-DLINUX -I/tmp/zxid-0.20 -I/usr/local/ssl/include -I/usr/local/include
-c -o zxid.o zxid.c
zxid.c:34:23: curl/curl.h: No such file or directory
In file included from zxid.c:38:
zx.h:26:25: openssl/rsa.h: No such file or directory
...
What happened is that OpenSSL for some reason is not in the location where standard OpenSSL distribution would install it (as indicated by -I/usr/local/ssl/include flag that ships with ZXID Makefile). You need to determine where OpenSSL is installed in your case. You can use
find / -name rsa.h -ls
to locate candidates.
For example, if it turns out that OpenSSL is installed in /opt/ssl, then you need to create a localconf.mk file that indicates this location:
echo OPENSSL_ROOT=/opt/ssl >localconf.mk
There are several other make variables you may need to tweak. In the above example, we also notice that libcurl was not found where expected. This would be fixed like this
echo CURL_ROOT=/opt/curl >>localconf.mk
Net result? ZXID does not try to guess where the libraries are. It makes you do the foot work of locating the correct libraries (some people have more than one instance installed) and prepare the localconf.mk. This may seem like a lot of work, but in my experience, fixing GNU autohell configure scripts that guess wrong is thousand times more frustrating. The system is dumb by design so you, as a human, do not have to try to second guess it - you are in control.
gcc -g -fpic -fmessage-length=0 -Wno-unused-label -Wno-unknown-pragmas -fno-strict-aliasing -D_REENTRANT -DDEBUG -DUSE_CURL -DUSE_OPENSSL -DLINUX -I/c/cvs/zxid_cvs -I/usr/local/ssl/include -I/usr//include -c -o c/zx-a-aux.o c/zx-a-aux.c c/zx-a-aux.c: In function "zx_NEW_a_Action": c/zx-a-aux.c:80: error: "zx_a_Action_ELEM" undeclared (first use in this function)
This happens because c/zx-const.h was misgenerated (it should not happen at all if you do not supply ENA_GEN=1) and does not include the necessary defines. c/zx-const.h should have more than 1900 lines and look something like
/* generated file, do not edit! zx_ _ATTR */ #ifndef _zx__ATTR #define _zx__ATTR #define zx_use_ATTR 0 #define zx_used_ATTR 1 #define zx_sequence_ATTR 2 ... #define zx_wantDSEPR_ATTR 347 #define zx_ZX_TOK_NOT_FOUND_ATTR 348 #define zx__ATTR_MAX 349 #endif /* generated file, do not edit! zx_ _ELEM */ #ifndef _zx__ELEM #define _zx__ELEM #define zx_ds_Y_ELEM 0 #define zx_gl_Y_ELEM 1 #define zx_gl_esrd_ELEM 2 ... #define zx_wst_OnBehalfOf_ELEM 1629 #define zx_ZX_TOK_NOT_FOUND_ELEM 1630 #define zx__ELEM_MAX 1631 #endif
Should not happen with version 0.21 or later. See zxidnoswig.h for explanation of the problem.
Perl modules generally want to be compiled with the same C compiler and options as were used to compile perl itself (see perl -V). If this happens to be different than the compiler you have defined in CC variable (gcc by default, near top of Makefile or in localconf.mk), you may get an error like:
cd Net; perl Makefile.PL && make Warning: -L.. changed to -L/home/sampo/zxid/Net/.. Writing Makefile for Net::SAML make[1]: Entering directory `/home/sampo/zxid/Net' cc -c -I.. -I/apps/openssl/std/include -I/apps/include -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe -Wdeclaration-after-statement -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -march=i586 -mtune=i686 -fmessage-length=0 -Wall -D_FORTIFY_SOURCE=2 -g -Wall -pipe -DVERSION=\"\" -DXS_VERSION=\"\" -fPIC "-I/usr/lib/perl5/5.8.8/i586-linux-thread-multi/CORE" SAML_wrap.c /bin/sh: cc: command not found make[1]: *** [SAML_wrap.o] Error 127 make[1]: Leaving directory `/zxid/Net' make: *** [samlmod] Error 2
Solutions
Compile zxid with compiler that was used for perl, e.g.
make CC=the-compiler-that-perl-wants
Recompile perl using the compiler that you want to use for zxid
Tinker with PATH environment variable so that both C compilers are found. However, using two different compilers is not really supported.
In general these types of problems happen when you use perl installed by your distribution, but have later compiled a gcc of your own. It may even be that you never installed the distribution cc - in that case consider installing it and then trying approaches 1 or 3.
A similar situation can arise with incompatibility of the compiler and options used for dependency libraries, such as OpenSSL or libcurl, and those used for compiling zxid itself.
You need to symlink zx to zxid source directory, thus
ln -s . zx
If you do not have it, then you will get a lot of file inclusion errors for headers that are supposed to be in path starting by zx/
The symlink is there to keep all hand written source files on top level of directory for ease of development, yet allow inclusions to go through zx subdirectory. When zxid is installed, it goes to /usr/include/zx. Hence the symlink keeps the includes the same whether developing or using installed version.
If you compile zxid with compiler warnings turned on (CFLAGS += -Wall), you will see quite a number of warnings, most of which are unwarranted. Since the warnings are unwarranted, I ship zxid Makefile with warnings turned off. If this bothers you, feel free to investigate the warnings and report to me any issues you uncover.
Following warnings in partuclar are unwarranted:
Any unusued variable warnings, especially in generated code. Most common of these is se variable (see enc-templ.c).
"Suggest parenthesis around assignment when used as truth value." I rely on C language operator precedence. Also, in most cases the assignment is the only expression in the truth test - there simply is no opportunity for ambiguity -- and no justified case for gcc to warn about this.
"Suggest parenthesis around && when used in ||". I rely on C language operator precedence, hence the suggestion is redundant.
Some warnings you may want to worry about
"int format, long int arg". On 32 bit platforms int and long are both 32 bits so this warning is not an issue. On 64 bit platforms, however, there may be cause for worry.
javac -J-Xmx128m -g zxid.java zxidjava/*.java zxidjava/zxidjni.java:159: cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni
public static zx_str zx_rsa_pub_enc(zx_ctx c, zx_str plain, SWIGTYPE_p_p_void rsa_pkey, int pad) {
^
zxidjava/zxidjni.java:164: cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni
public static zx_str zx_rsa_pub_dec(zx_ctx c, zx_str ciphered, SWIGTYPE_p_p_void rsa_pkey, int pad) {
^
zxidjava/zxidjni.java:169: cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni
public static zx_str zx_rsa_priv_dec(zx_ctx c, zx_str ciphered, SWIGTYPE_p_p_void rsa_pkey, int pad) {
^
zxidjava/zxidjni.java:174: cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni
public static zx_str zx_rsa_priv_enc(zx_ctx c, zx_str plain, SWIGTYPE_p_p_void rsa_pkey, int pad) {
^
This was due to missing SWIG generated classes. Probably interrupted file transfer.
javac -J-Xmx128m -g zxid.java zxidjava/*.java zxid.java:24: cannot find symbol symbol : method new_conf(java.lang.String) location: class zxidjava.zxidjni
cf = zxidjni.new_conf("/var/zxid/");
^
zxid.java:27: cannot find symbol symbol : method url_set(zxidjava.zxid_conf,java.lang.String) location: class zxidjava.zxidjni
zxidjni.url_set(cf, url);
^
zxid.java:28: cannot find symbol
jar cf zxidjava.jar .class jar cf /tmp/zxidjava.jar zxidjava/.class
javac -J-Xmx128m -g zxid.java zxid.java:187: cannot access zxid_conf bad class file: /Library/Java/Extensions/zxidjava.jar(zxid_conf.class) class file contains wrong class: zxidjava.zxid_conf Please remove or make sure it appears in the correct subdirectory of the classpath.
public static int mgmt_screen(zxid_conf cf, zxid_cgi cgi, zxid_ses ses, char op)
^
1 error
Underscore in linking error
./zxid-java.sh Start... Exception in thread "main" java.lang.NoSuchMethodError: zxidjava.zxidjni.new_conf(Ljava/lang/String;)Lzxidjava/zxid_conf;
at zxid.main(zxid.java:24)
This was due to finding some old copies from system paths.
java -classpath .:zxidjava -Djava.library.path=zxidjava zxid Start... Exception in thread "main" java.lang.UnsatisfiedLinkError: _zxid_new_conf
at zxidjava.zxidjniJNI._zxid_new_conf(Native Method)
at zxidjava.zxidjni.new_conf(zxidjni.java:586)
at zxid.main(zxid.java:24)
If your Unix platform is not mentioned, you should try saying just
make
which will compile with Linux options. These options actually are pretty close to pure POSIX compile so you should get very close to working configuration.
Native development platform. Just say
make
Seems there are some "improvements" that distributions have made. ZXID adopts the policy of expecting dependency modules where the module author meant it to be installed by default - for example OpenSSL by default installs in /usr/local/ssl (naming is historic, but has stuck). Many distros tinker with these paths. This means you need to create a localconf.mk.
Redhat used to have an issue with Net::SAML (make samlmod). This has since been fixed, please see zxidnoswig.h for explanation.
No doubt, distros will eventually pick up ZXID and provide it as a package. Once that happens they will solve any path issues accoring to their disto policy and that is fine, just do not ask me to comply with any such policy.
No target available on Makefile, but a port is available from http://www.freshports.org/security/zxid/
make TARGET=sol8 make TARGET=xsol8 # Cross compile for Solaris (e.g. on Linux host)
make TARGET=macosx
make zxid.dll TARGET=xmingw # Cross compile on Linux host (best supported) make zxid.dll TARGET=mingw # Native compile for mingw target in Cygwin environment
Eitherway, the net result is native Windows DLL that does not have Cygwin library dependencies or GPL encumberation.
See Makefile for further mingw notes.
make TARGET=cygwin
Very experimental (as of Oct 2007) native build for Cygwin.
Cygwin appears to not have neither flock(2) nor lockf(2). This is strange because at least one of these is implemented on MinGW. Current workaround is to define flock() to be empty macro. This of course means there is no file locking. There are 3 known races where things can go wrong
Audit logs can get garbled. This does not stop ZXID from working, but may make log analysis more complicated.
Auto-CoT metadata writes can get garbled. This is very unprobable, but if it happens, the ZXID deployment will not work towards affected IdP. Nothing to worry about really.
Locking is used to protect against updates of zxid.conf while zxid is running. Again any corruption is very unlikely. Nothing to worry about.
The results of Cygwin compile may be GPL encumbered due to libraries.
Never been done (as of Oct 2007), but probably this is not very difficult given that MinGW port already has addressed many Windows platform issues. Please send any success reports, and receipes, my way.
Q: In mod_auth_saml, what is the relation between ZXIDConf and httpd.conf?
A: httpd.conf can contain ZXIDConf directives. Those directives are processed as if they came from /var/zxid/zxid.conf file (which is processed first, before and ZXIDConf directives), except that if you specify ZXIDConf "PATH=/your/path", this triggers reporcessing of the zxid.conf (from the new path).
Q: In mod_auth_saml, what is the relation between the port in ZXIDConf and the port in the httpd.conf?
A: The ports must agree. ZXID configuration must match the way the Apache layer is configured.
Q: Multiple roles of same entity, acting as SP, WSC, and WSP for different services
Asa:
Part of what you are saying is that the service registration is WSC. This is rather confusing since the case is a WSP acting as a WSC of the Discovery Service. For the ClientLib thus far, I have chosen to think of service registration as a WSP to WSP. What is the downside to this approach?
Conor:
Service registrations can't be done WSP to WSP with any Liberty protocol (in fact, we don't define any such method of invocation as the invoking party is always a WSC for the intent of that message - there's no problem with a WSP in turn being a WSC of another service instance, just
Right. You can don WSC role whenever convenient. There is nothing confusing about WSP of one service being WSC of another service. Perhaps the confusion would be avoided if everybody fully qualified their descriptions until common convention about less than fully qualified roles emerges.
Entity E1, an ID-DAP WSP (primary role), will act as Discovery WSC (secondary role) to perform metadata registration. This same entity E1 will also have SP interface (another secondary role) which allows the user to trigger discovery association, again E1 acting in secondary role of Discovery WSC.
No confusion as far as I can see.
When I try accessing https://sp1.zxidsp.org:8443/zxidtest.sh nothing happens!
Assuming you have the web server correctly running, the most common gotcha is that zxidhlo has dynamic linking problem. See ?ZXID-Installing-CannedTutorialRunningZXIDasCGIundermini_httpd-AccessingZXID? subsection "Dynamic Linking Problems", for explanation and resolution.
Single Logout does not end the IdP session (i.e. IdP does not force you to supply password when you do SSO next time).
Usual cause is that the management form (the one with the SLO buttons) does not have correct or any session ID. Do a view source on the the page and look for field called "s". The session ID is supposed to be extracted from the Single Sign-On result. For zxid_simple() you need to parse the returned LDIF and take the sesid. Pass that to zxid_fed_mgmt() as second argument.
Login buttons do nothing.
A possible cause is that the entity ID is not passed from the IdP selection form. If the form is using POST method, you must make sure you actually read the HTTP body and pass its contents to the zxid_simple() as the qs argument.
The SP Login, a.k.a. IdP selection, page shows, but SSO does not work
Your configuration does not match actual URL used to access the zxid system. For the zxidhlo family of examples you MUST edit the configuration string to match your situation. Watch out for domain name and port number.
Connectivity issue prevents IdP from fetching metadata. Make sure your domain name is resolvable at IdP (e.g. add it to /etc/hosts). See also next point.
IdP is not configured to get your metadata automatically. You have to configure your metadata to the IdP manually. How to do this depends on IdP product. Do not ask us.
You supplied IdP URL that, in fact, is not the well known location for fetching IdP metadata. Or the IdP does not have well known location enabled. In the latter case you will need to install the IdP metadata manually . See [SAML2meta] section 4.1 "Publication and Resolution via Well-Known Location", p.29, for normative description of this method.
Connectivity issue at web browser level. Make sure your web browser can resolve both SP and IdP domain names. Edit /etc/hosts as needed on the machine where the browser runs.
Personal firewall blocks access. Check firewall set up on
browser machine
SP machine
IdP machine
The SP Login, a.k.a. IdP selection, page does not show at all
Connectivity issue at web browser level. Make sure your web browser can resolve both SP and IdP domain names. Edit /etc/hosts as needed.
Personal firewall blocks access. Check firewall set up on
browser machine
SP machine
You deployed the zxid in some other URL than you thought. Double check your webserver or servlet container configuration and be sure you understand where zxid is supposed to appear. Be sure you are editing the right configuration - some people run multiple web servers in their machine and get confused about which one actually is active on which port and where the configuration files are located.
ZXID lacks execute permissions, dynamic link libraries are missing (use "ldd zxid" to check), or CGI permission setup prevents it from running. See previous bullet.
Mystery configuration problems. Double check /var/zxid/zxid.conf or consider removing it if you do not understand what it does. Double check the conf string if using zxid_simple() interface.
Writes a user...
tb77f96c0 zxidmeta.c:352 zxid_get_ent_by_sha1_name zxid d Trying sha1_name(cot) open (vopen_fd_from_path): No such file or directory
Did you create the /var/zxid hierarchy (make dir) and make sure your web user (nobody?) has write permission to the log directory? Or did you configure it to use some other directory than /var/zxid?
What is this /var/zxidcot directory?
It is supposed to be /var/zxid/cot
When configuring PATH, did you forget trailing slash? E.g.
"PATH=/var/zxid&URL=..." # WRONG!
"PATH=/var/zxid/&URL=..." # Right
If configuration appears to be prematurely truncated, then see if you need to adjust ZXID_MAX_CONF (default 4KB) in zxidconf.h and recompile.
How to decode auto_flags
0x1d54 1 = debug; d = FORMT + FORMF + MGMTC; 5 = METAC + LOGINC; 4 = SOAPC
A frequent concern among the business people and lawyer types is whether the architecture provides for consent by the user. Usually this is related to (avoidance of) liability. If the system can be said to have gathered the consent of the user, we are safe.
Unfortunately the standards do not mandate an uniform user interface, thus there is no single specific way how the consent is gathered or determined: it depends from business situation and application to another. Fortunately the Liberty and SAML 2.0 architectures provide plenty of ways and hooks to gather and convey the consent. Consider the following:
When arriving to SP, user chooses IdP for SSO. This act of course manifests user's intent to perform SSO.
IdP can ask the user whether he wants to perform SSO to the SP (IdP can make this question even if user is already logged in to the IdP, though most demos omit the question in the already logged in case).
At this point the IdP may also ask whether the user wants to create a federation so that the SP can track the user. Creating federation is consenting to be tracked by the SP.
If the federation already exists, the IdP can still offer a choice: should the federation be used this time, i.e. does the user consent to be tracked this time specifically.
If user does not consent to federation and use of federation this time, but still consents to SSO, the SSO will be made using a temporary name ID.
If user gives any Personally Identifying Information to the SP (beyond the federated pseudonym), then the SP may be able to "connect the dots" and correlate user's actions on the SP with his actions in some other systems (technically this is called collusion).
In a very technical sense users should be aware of this risk or the implication and therefore by providing such information they are effectively consenting to be correlated across systems.
However, lawyers would probably say that if the SP intends to correlate, it should state so to the user at the time the information is asked so that the user can make an informed decision. If, after being informed, the user still supplies the information, then user is clearly consenting to the information being used for the stated purpose, i.e. correlation.
When user starts to use an ID web service, the user is consenting to this service being visible to at least some parties (why use the service if you did not intend this).
To make this consent explicit, the user interface of the ID Web Service can ask.
Also, the Discovery Service can ask consent using the Liberty Interaction Service. It is quite appropriate for the DS to ask this consent because it allows the ACL to be set correctly right from the beginning, when the service is registered.
When the user later accesses an SP that needs to contact an ID Web Service, it could be construed that the user, by using the SP at all, is effectively consenting that the SP may access the ID Web Services of the user.
If this is not enough, the Discovery Service can use the Interaction Service on per service invocation basis to ask if the user consents to the specific request.
Finally, the actual ID Web Service can also invoke the Interaction Service to ask the user to consent to the specific request, or otherwise enforce its policies.
When using People Service, the inviter (Alice) consents to the access by the invitee (Bob) by requesting an invitation string from the system.
Once the invitation has been sent (and accepted by invitee) there is no easy way to collect consent from inviter on per request basis. For example Alice may not be online at the time when Bob accesses her resource.
Alice can later revoke Bob's invitation, but in the window between Alice sending the invite and revoking it, Bob can access Alice's resource without Alice actively consenting to every access.
Of course the resource can implement ACL policies, like only allowing Bob to access the resource a limited number of times, such as once.
When the invitee (Bob) uses inviter's (Alice's) ID Web Services (resources), Bob has consented to some form of tracking by Alice's resources by accepting the invite. Further consent may be obtained by Bob's own IdP, see bullet 2.
Here is a rudimentary decision tree for deployment planning
List your applications
Any provided by external partner?
Non web apps
Document your existing identity stores and approaches to
User provisioning (when someone is employed)
Application provisioning (when someone starts using app)
Authorization: how do you know who is supposed to be doing what?
Deprovisioning: what happens when someone is fired?
Login? Per app? Harmonized user names? Enterprise SSO?
Document your goal: federated SAML SSO über alles :-)
Do you want to run IdP?
Could you out-source IdP?
Will your partners / customers be running their own IdPs?
Will you participate (or run) single CoT or do you need to consider cross CoT inter-operation (e.g. IdP proxying)
To be continued...
Metadata import to IdP?
What I usually do is
cd /opt/SYMfiam/3.0.x/conf/symdemo-idpa echo 'sp: zxid-sp1$https://sp1.zxidsp.org:8443/zxid?o=B$$' >>cot.ldif
Double check with text editor that the file is sensible. Note that the single quotes are essential as the dollars are to be interpretted literally, as separators.
cd pem wget https://sp1.zxidsp.org:8443/zxid?o=B >zxid-sp1.xml
Here the intent is to fetch the metadata from the SP and store it in a file whose name (without .xml extension) matches the first component of the sp: line. I am not 100% on the wget syntax. You can also use browser to fetch the metadata and simply Save as under the correct name.
cd /opt/SYMfiam/3.0.x/conf/symdemo-idpa/start.sh restart
This should restart the IdP server process and cause a refresh of the metadata it may have cached. You may want to
tail -f /opt/SYMfiam/3.0.x/conf/symdemo-idpa/log/debug.log
to see if its getting indigestion.
N.B. FIAM seems to have NameID encryption on by default, Turn this off by editing slimidp.ldif:
encnids: 0
If this is not done, the SSO will fail (with what appears like signature error).1x
Following are known limitations. We document them here because we do not plan to fix them in near-to-medium future.
Unknown XML attributes are not sorted according to rules of exc-c14n. Instead they appear always after known XML attributes and in the order they happen to be in the linked list.
Work around: Add the attribute to schema (.sg) and regenerate and rebuild.
XML canonicalization
CRLF to LF
Single quote to double quote
Special character handling, entity escapes?
"Random number generator not seeded!!!"
This warning indicates that randomize() was not able to read /dev/random or /dev/urandom, possibly because your system does not have them or they are differently named. You can still use SSL, but the encryption will not be as strong. Investigate setting up EGD (entropy gathering daemon) or PRNG (Pseudo Random Number Generator). Both are available on the net.
"msg 123: 1 - error:140770F8:SSL routines:SSL23_GET_SERVER_HELLO:unknown proto"
SSLeay error string. First number (123) is PID, second number (1) indicates the position of the error message in SSLeay error stack. You often see a pile of these messages as errors cascade.
"msg 123: 1 - error:02001002::lib(2) :func(1) :reason(2)"
The same as above, but you didn't call load_error_strings() so SSLeay couldn't verbosely explain the error. You can still find out what it means with this command:
/usr/local/ssl/bin/ssleay errstr 02001002
This is normal behaviour if your private key is encrypted. Either you have to supply the password or you have to use unencrypted private key.
One way to remove password is
openssl rsa -in key.pem -out keyout-nopw.pem
For this to work, key.pem must contain only the private key. On the other hand, for ZXID to work, the file must have both certificate and private key. You will need to use your favorite text editor to split them for password removal and then to join them for use.
Scan OpenSSL.org for the FAQ for full explanation on how to remove password from the private key.
Sometimes you get warning messages (in browser) or signature validation errors (in IdP end) because the Subject field of the certificate does not match your actual domain name. You can check this with
openssl x509 -text </var/zxid/pem/ssl-nopw-cert.pem | grep Subject:
and then look at "CN=" part (CN means Common Name and this by convention has to match domain name of your server). If the domain name is different, then you need to obtain a certificate with correct domain name, see next question.
N.B. As of OpenSSL 0.9.8d (2007) it seems that some certificates issued by Equifax can not be decoded using openssl x509 tool, resulting ":Expecting: TRUSTED CERTIFICATE" error. Trying openssl asn1parse also results in error: "SN1_get_object:header too long". Curiously, these certificates still seem to work for encryption and decryption, as witnessed using the procedure for checking whether certificate and private key belong together (see below).
ZXID ships with zxid.pem which gets by default copied to /var/zxid/pem under various different names. This is fine for testing, but disastrous for production or security sentitive use as the private key corresponding to zxid.pem certificate is of public knowledge (it is distributed with every copy of ZXID) - it offers no security and no non-repudiation what-so-ever.
For production or security sensitive install you need to either
Obtain certificates from an official certification authority, usually a commercial one. ZXID uses same certificate format as Apache (i.e. the pem format), so aquiring certificates is easy. Or,
Generate your own certificate. The simplest case is a self signed certificate:
openssl req -new -x509 -nodes -keyout pkey.pem -out cert.pem
cat cert.pem pkey.pem >/var/zxid/pem/ssl-nopw-cert.pem
The cat step is there because you need to supply both certificate and the private key in same file for ZXID to understand it.
Warning: Although ZXID wants to see the private key in the same file as the certificate, you MUST NOT give this concatenated file to any outsider. Others have legitimate need to know your certificate, but they MUST NOT know your private key. If they ask, you should take special care to delete the private key from the file prior to giving it to them. Often those who need to get your certificate, actually need your metadata: just tell them to fetch it from the Well Known Location URL (i.e. the Entity ID of your SP). ZXID will never leak the private key to the metadata.
You can use openssl(1) tool to test if a keypair is good
echo boo >foo openssl rsautl -encrypt -pkcs -in foo -out foo.enc -inkey enc-nopw-cert.pem openssl rsautl -decrypt -pkcs -in foo.enc -out foo2 -inkey enc-nopw-cert.pem diff foo foo2
This is due to locale setting. Try
export LANG=C
This will disable any UTF-8 processing in sprintf().
In several SAML profiles a HTTP redirect is performed to send the user to other party, usually with a request or response in the query string.
A mysterious error is when you see yourself receiving as input the stuff that was supposed to be sent to the other. The way this happens is if for some reason the other party's URL can not be determined, then the Location header will only consist of the query string that you are trying to send. Without domain name part of the URL, the browser will redirect back to the web site where the redirection came from. This is called "local redirect" and is usually the cause of you receiving your own output as input.
To fix this, make sure you have the other site's metadata and make sure it parses and loads correctly. If that does not resolve the problem, see if the metadata has any binding for the operation you are trying. No binding will result in no URL.
Possible causes:
No common ground in terms of cipher suites. While venerable SSL2 cipher suite SSL_RSA_WITH_RC4_128_MD5 works with legacy browsers, some "modern" software do not support this out of box.
[SAML2conf], sections 4 "XML Digital Signature and XML Encryption" and 5 "Use of SSL 3.0 and TLS 1.0" mandate some algorithms, but unfortunately these do not overlap with SSL2 legacy use. The latter section mandates TLS_RSA_WITH_3DES_EDE_CBC_SHA and SSL_RSA_WITH_3DES_EDE_CBC_SHA.
To make matters more complex, enabling all cipher suites at once has historically caused some vendor implementations of SAML2 to fail. As bugs get fixed, this may improve. (Information as of late 2007.)
OpenSSL SSLv23 autonegotiation mode (which can also autonegotiate to TLSv1) works mostly great, but some vendor implementations of SSL have trouble with this. Apparently the only way to work around them is to disable the autonegotiation and hardwire the protocol to TLSv1 or SSL3. (Information as of OpenSSL 0.9.8g, Feb, 2008)
On some platforms wireshark(1) network sniffer reports TCP layer checksum errors even when communications work fine. This is probably a bug in those wireshark(1) installations (as of early 2008, unknown version, difficult to reproduce). Please note that getting TCP checksums wrong at user land networking code is (nearly?) impossible. It would have to be a kernel bug - and that is unlikely.
wireshark(1) hint: Right click on SSL packet and choose "Decode as..." and then select SSL, to see the details of SSL/TLS handshake that can cause the handshake failures.
Some implementations of SSL report handshake failure when they are unable to establish trust in certificate. Technically this is a trust failure and the handshake happened OK - they just report it in a misleading way. The fix is to either supply appropriate CA certificate (chain for multilevel) or relax the trust check.
One sure fire way to break SSL or signing is to mismatch certificate and private key. Sometimes this happens due to practise of storing certificate, its CA certificates, and the private key in the same file. If you suspect this, just remove the CA certificates so that the PEM file only contains certificate and its private key.
Also any manual key exchanges are much more prone to error than ones effectuated via automatically generated metadata.
Finally, sometimes the OpenSSL PEM parsing code can not digest line endings that are not natural for the platform. On Unix machines, running dos2unix(1) on the PEM file may help.
To adjust cipher suite and SSL version parameters, first see http://www.openssl.org/docs/apps/ciphers.html and the man page for SSL_CTX_set_cipher_list(3) at http://www.openssl.org/docs/ssl/SSL_CTX_set_cipher_list.html
Then diagnose whether adjustment is needed in SSL server or client role:
For SSL server role, you need to consult the documentation of the web server under which you run ZXID.
For SSL client role, you need to consult the documentation for the libcurl(3) package, which uses OpenSSL in its guts.
Note: ZXID and Apache (the web server you are likely to use) use main stream OpenSSL package for SSL and crypto. While bugs are always possible, OpenSSL is considered stable. Many newer implementations of SSL or crypto, e.g. for Java, are not nearly as well tested and are more likely to contain bugs or limitations. Many vendors do not disclose what SSL or crypto code base they use - you should suspect the worst.
What is Schema Grammar (.sg) and why are you using it?
Schema Grammar is a compact formal description of XML documents. It is mostly bidirectionally convertible to XML Schema (XSD) and captures the useful essence of most XML schemata.
Schema Grammars are intuitive and compact, often allowing the essence to be understood at glance, and even most complex cases being only about 50% of the volume of the corresponding XSD.
We use Schema Grammar descriptions because they are more human readable than XSD and still equally amenable to automated code generation.
Schema Grammar descriptions are usually converted using xsd2sg.pl, which is part of the PlainDoc distribution.
N.B. You do not need xsd2sg.pl or PlainDoc if you just want to compile and use ZXID.
What is PlainDoc (.pd)?
PlainDoc is a document preparation system that uses intuitive plain text files with minimal markup to generate PDF and HTML outputs.
We use PlainDoc because it makes it easy to maintain documentation.
N.B. You do not need PlainDoc if you just want to compile and use ZXID.
How come zxid is so heavy to compile?
SAML 2.0 and related specs have a lot of functionality and detail, even if you really only need 1% of it. We do not wish to arbitrate which functionality is best or most needed, so we simply provide it all.
A lot of the code is generated, thus the input for C compiler is well in excess of half a million lines of code (of which only about 6k were written by a human).
Some of the generated files are gigantic, e.g. Net/SAML/zxid_wrap.c is over 380k lines. Compiler has to process all of this as a single compilation unit.
gcc and gnu ld were, perhaps, not designed to process this large inputs efficiently. Often the implementation strategy of keeping everything in memory will cause a smaller machines to swap.
My 1GHz CPU, 256 MB RAM machine definitely swaps and thus takes about 45 minutes to compile all this stuff.
I recommend at least 1GB RAM and 3GHz CPU for development machine. On such machine, you should be able to build in about 10 min.
Why do you not use ./configure and GNU autoconf?
autoconf is not for everyone. World does not stop without autoconf. Or indeed need autoconf. It is Yet Another Dependency I Do Not Need (YADIDNN).
I find the GNU autoconf stuff much more difficult to understand than my own Makefile. Why should I debug autoconf when I could spend the time debugging my Makefile or the actual code?
I find resolving problems much easier at source code and Makefile level than trying to debug a million line script generated by some system I do not understand (perhaps some hardcore autoconf advocate could try to convince me and educate me, but I doubt).
My policy is to only support systems I have first hand experience with, or I have trustworthy friends to rely on. It does not help me to have a system that tries to guess gazillion irrelevant variables to an unpredictable state. It's much easier to stick to standards like POSIX and make sure you have predictable results from predictable inputs.
If the deterministic and predictable results are wrong, they can at least be debugged and fixed with a finite amount of work.
Supporting all relevant systems manually is not that much of work. The inhabitants of the irrelevant systems can support themselves, probably learning a great deal on the side.
A recent (Sept 2006) conversation that touched on the aims of ZXID project:
So just generally, what are your goals for it, are you interested in making it work well with what other people are producing (e.g. SAML -> WSF cross-over), etc? I'm certainly assuming the answer's yes to that.
I aim at full stack client side implementation. ID-FF, SAML 2.0, WSF (both versions). The generation technique I use will yield the encoders and decoders for both WSP and WSC, but the hand written higher level logic will at first be only written for SP and WSC. Some WSP support has now been written as well (complete WSP support was completed as of July 2007).
It is Apache licensed project, of course, so if someone contributes the IdP and WSP capabilities, I'll merge them into the distribution.
I am interested to have it working with other people's code at 3 levels:
Over-the-wire interoperability
I have split the functionality of the SP from the WSC such that zxid SP could probably be used with someone else's WSC and someone else's SP would reasonably easily be able to use zxid WSC.
Interfaces to non IdM parts of the complete system, typically used to implement the application layer, shall be plentiful: C/C++ API, Net::SAML/mod_perl, php - whatever you can SWIGify.
One thing I am NOT interested in is "layered" stack. I strongly believe it's better each vertically integrated slice is implemented by one mind. Thus, except for lowest HTTP, TLS, and TCP/IP layers, my SP, or WSC, or WSP, handles the whole depth of the stack - SOAP, signature, and app interface layers (of course the actual app should be its own layer and probably user written). That is by design.
I have found in practise that if you attempt a layered stack, you have impedance mismatches between the modules at different layers because they were designed and written by different minds. By having vertical integration I avoid impedance mismatches. This is the reason why monolithic TCP/IP implementations tend to be better than explicitly layered, such as the streams approach.
Now, if someone else wanted to take my generated encoders and decoders and use them as a "layer" in their layered stack, I guess I would not have any issue. If you do that, please let me know because I would have to commit to API stability at that layer. I am willing to do that once there are real projects that depend on it, but until then I still may redesign those APIs, after all, I am at revision 0.4 :-)
In the end, it seems that ZXID is actually somewhat layered approach - what I mean by "vertical integration" is that all the layers are designed and controlled by the same mind.
BTW, I gather that it's SAML 2.0 at the moment, which I can't offer any test capability for, but if you get to SAML 1.1, I'm happy to set up some kind of IdP test capability for that.
In SSO world SAML 1.1 and ID-FF 1.2 capabilities are definitely on the
road map. In ID-WSF world, I'll probably start with 2.0 DS-WSC (don't
we all) followed by ID-DAP WSC and then tackle 1.1 after
that.
There is a lot of commonality that is not leveraged, especially in the way service end points are chose given the metadata. The descriptors are nearly identical so casting them to one should work.
Many of the SAML2 responses are nearly identical. Rather than construct them fully formally, we could have just one "SAML any response" function. Perhaps this could be supported by some schema grammar level aliasing feature: if an element derives from base type without adding anything at all of its own, we might as well only generate code for the base type.
Namespace aliasing scheme would allow us to consider two versions of schema the same. It seems to be fairly common that the schema changes are so minor that there is no justification for two different decoding engines.
Destination XML attribute is needed in redirect and POST bindings.
Assertion//SubjectConfirmationData/@InResponseTo XML attribute is needed in SSO assertions, unless the SSO was unsolicited. SAML is not very explicit about this, [SAML2core], ll.729-732 describes it as optional, but [SAML2prof], ll.580-582 and ll.559-560 seem to imply this requirement.
Some deployments use POST binding for many more things than officially sanctioned by SAML [SAML2conf], Table 1 "Possible Implementations", p.6. None of the offical profiles, see [SAML2conf], Table 2 "Feature Matrix", p.9, require support for POST for sending or receiving Single Logout or Manage NameID requests. Nor is sending AuthnRequest using POST officially sanctioned. Using artifact profile for anything else than fetching the SSO assertion is not official. Never-the-less, some of these bindings are perfectly implementable and some deployments actually use them. ZXID may support some of them, especially the POST bindings, if it is easy to do so, but we make no commitment beyound official SAML conformance.
In SAML SOAP bindings it is bit unclear if the caller needs to be authenticated. Currently ZXID solves this by signing the SOAP requests (see SSO_SOAP_SIGN configuration options). Other approaches are using HTTP Basic authentication, using Client-TLS, or simply not authenticating the peer.
Interpretation of metadata KeyDescriptor/EncryptionMethod
Algos on [SAML2conf], section 4.2 "XML Encryption Algorithms", ll.252-253.
The interpretation in [SAML2meta], section 2.4.1.1 "Element
Since the
The selection of protocol binding for return path of SSO is non-trivial. The Authentication Request may specify any number of parameters like ProtocolBinding or Index.
When passing around Name IDs or storing them in database, remember to store all components, including NameQualifier and SPNameQualifier.
Single Logout: IdP should not call originator of SLO when it is logging out everybody.
Each entity chooses its own Entity ID. When you are setting up a SP, you choose your Entity ID and the IdP(s) MUST be able to adapt to your choice. Similarily, an IdP decides its own Entity ID and all SPs MUST be able to adapt to it.
Entity IDs MUST be unique within a Circle of Trust (CoT). Given that CoT relationships may change from time to time, its best to choose Entity ID so that it is globally unique. If Entity ID contains a domain name as a component, then the globally unique property tends to be enforced by the domain name allocation system.
Entity ID SHOULD be the Well Known Location (WKL), i.e. the URL from which the metadata can be fetched.
Providing metadata by URL, ideally by the Entity ID, SHOULD always be enabled. This greatly facilitates configuration.
N.B. zxid.org does not yet support Infocard, but since we are starting the investigation, we thought to share some of it
DigitalMe by Bandit project is an open source Infocard implementation, providing functionality roughly similar to CardSpace. You can download it from
http://www.bandit-project.org/index.php/Digital_Me
rpm2cpio digitalme-0.4.1238-2.1.i586.rpm | cpio -di
For one InfoCard aware IdP, please see: http://www.cdatazone.org/index.php?/archives/27-Managed-Infocard-Demo.html
Register at the IdP site (e.g. https://www.ctindustries.net/icard/index.php)
Download the card ("Retrieve Managed Card" link (savea as "cdatamanaged.crd" by default).
Install the card to DigitalMe
Microsoft promises to not sue you: http://www.microsoft.com/interop/osp/default.mspx
I want to read the attributes that come in the assertion. how do I do that?
You get attributes back as an LDIF entry as return value of zxid_simple() The attributes are also available by reparsing the assertion, which gets stored in /var/zxid/rely hierarchy.
/var/zxid/ses/SuzZQS5Ub/.ses file contains the path to the assertion file.
Q:: In the zxid directory you store some users. what does the extension .mni stand for?
Why is the info stored? I assume it is some sort of local cache. I would like
to store the attributes there too. how do I do that?
The .mni file is used to support Manage NameID requests. In normal operation of ZXID it really is not needed, but to support some of the SAML conformance test requests it is needed.
Rather than store attributes in that directory, I'd suggest reparsing the assertion when you need them. But if you must, you could create a file of your own in that directory. We of course need a naming convention that prevents naming conflicts with future versions of ZXID: Your file extension should start by ".x-", for example: "attributes.x-attr"
Q:: The ldif returned by zxid_simple() is perfect for my needs. but
nothing is being stored in log\rely directory. could be some
configuration issue? also, can I have zxid automatically store the
ldif file returned zxid_simple()?
The log/rely should be populated by default, but if the directory structure itself is missing, may be it does not work. Try make dirs. Or check that web server user's permissions allow writing there.
Re ldif cached: the logic is supposed to be that the zxid_simple() will be called to protect every page, therefore its return value is available on every page.
If you do not call it every time, but instead bootstrap some sort of app specific session, then you would strore the LDIF (or the attributes parsed out of it) to that app specific session.
Mail the author until we get the list set up. Or volunteer a list :-)
Mail the author until we get bug tracking set up. Or volunteer.
We use CVS, but access needs to be manually configured and is not anonymous. If you contribute significantly, I will bother. Others can send patches (good way to show you are worthy of CVS access) to me. I've heard some mixed experiences about open source sites like sourceforge. If you run such site and want to host ZXID Project, please contact me.
If you just always want the latest source: get the tar ball from the downloads section. Trust me, this is still so much in flux that only the tar ball snapshots are in any usable state. CVS access just to get latest source would be pointless.
Following companies provide consultancy and support contracts for ZXID:
Large parts of ZXID code are generated from schema grammars which are a convenient notation for describing XML schmata. This chapter gives a sampling of some schema grammars that are currently implemented and distributed in the ZXID package. For fuller list, see sg subdirectory of the distribution or schemata.pd file.
Table 8:Schema grammar syntax
| Construct | Description |
|---|---|
| ee | Bareword signifies an XML element |
| @aa | At (@) prefix signifies an XML attribute |
| %tt | Percent (%) prefix signifies a complexType |
| &gg | Ampersand (&) prefix a signifies group |
| &@ag | Ampersand and at (&@) prefix signifies attributeGroup |
| xx -> %tt | Arrow (->) signifies reference to type that defines element or attribute |
| xx: ... ; | Colon (:) means that the definition of type follows immediately |
| ee | An element or attribute by itself means exactly one occurance is expected |
| ee? | Question mark (?) means the element or attribute is optional |
| ee* | Asterisk (*) means the element may appear from zero to infinite number of times (same as * in regular expressions) |
| ee+ | Plus (+) means the element must appear at least once, but may appear an infinite number of times (same as + in regular expressions) |
| ee{x,y} | The element must appear between x and y times (same as in regex) |
| ee | ee | The pipey symbol (|) means elements are mutually exclusive choices. |
| ee ee | Concatenation of elements or attributes means sequence |
| base( t ) | Introduce Extension base type (derive a type) |
| redef( .. ) | Redefine a type (using |
| mixed(1) | Mark a complex type as having mixed content type, i.e. strings and elements alternate |
| enum( ... ) | Introduce enumeration of xs:strings |
| any | xs:any, the XML arbitrary element extension mechanism |
| @any | xs:anyAttribute, the XML arbitrary attribute extension mechanism |
| target( ... ) | Define target namespace described by the schema |
| import( ... ) | Bring in other schemata and namespaces |
| ns( ... ) | Declare existence of another namespace (without importing it) |
# zxid/sg/saml-schema-assertion-2.0.sg # $Id: saml-schema-assertion-2.0.sg,v 1.8 2007-10-05 22:24:28 sampo Exp $ # # N.B. This file is not a direct conversion. Instead it has been manually edited to # make it simpler and to facilitate code generation. # 15.10.2006, extended AttributeValue schema to cater for bootstrap, Sampo Kellomaki (sampo@iki.fi) # 10.2.2007, added other types of assertions as potential Advice content --Sampo # 3.3.2007, added XACML support --Sampo target(sa, urn:oasis:names:tc:SAML:2.0:assertion) ns(xs,http://www.w3.org/2001/XMLSchema) import(ds,http://www.w3.org/2000/09/xmldsig#,http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd) import(xenc,http://www.w3.org/2001/04/xmlenc#,http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd) ns(di12, urn:liberty:disco:2003-08) ns(a, http://www.w3.org/2005/08/addressing) ns(sa11, urn:oasis:names:tc:SAML:1.0:assertion) ns(ff12, urn:liberty:iff:2003-08) ns(xasa, urn:oasis:xacml:2.0:saml:assertion:schema:os) ns(xsi, http://www.w3.org/2001/XMLSchema-instance) ns(idp, urn:liberty:idp:2006-12) &@IDNameQualifiers: @NameQualifier? -> %xs:string @SPNameQualifier? -> %xs:string ; BaseID -> %sa:BaseIDAbstractType %BaseIDAbstractType: &@sa:IDNameQualifiers ; NameID -> %sa:NameIDType %NameIDType: base(xs:string) @Format? -> %xs:anyURI &@sa:IDNameQualifiers @SPProvidedID? -> %xs:string ; %EncryptedElementType: xenc:EncryptedData xenc:EncryptedKey* ; EncryptedID -> %sa:EncryptedElementType Issuer -> %sa:NameIDType AssertionIDRef -> %xs:NCName AssertionURIRef -> %xs:anyURI Assertion -> %sa:AssertionType %AssertionType: sa:Issuer ds:Signature? sa:Subject? sa:Conditions? sa:Advice? sa:Statement* # *** how to express * for choice sa:AuthnStatement* sa:AuthzDecisionStatement* sa:AttributeStatement* xasa:XACMLAuthzDecisionStatement* xasa:XACMLPolicyStatement* @ID -> %xs:ID @IssueInstant -> %xs:dateTime @Version -> %xs:string ; Subject -> %sa:SubjectType %SubjectType: sa:BaseID? # Only one of the IDs should occur sa:NameID? sa:EncryptedID? sa:SubjectConfirmation* # This is more lax than SAML spec ; SubjectConfirmation -> %sa:SubjectConfirmationType %SubjectConfirmationType: sa:BaseID? # Only one of the IDs should occur sa:NameID? sa:EncryptedID? sa:SubjectConfirmationData? @Method -> %xs:anyURI ; SubjectConfirmationData -> %sa:SubjectConfirmationDataType %SubjectConfirmationDataType: base(anyType) ds:KeyInfo+ @Address? -> %xs:string @InResponseTo? -> %xs:NCName @NotBefore? -> %xs:dateTime @NotOnOrAfter? -> %xs:dateTime @Recipient? -> %xs:anyURI @xsi:type? @any ; %KeyInfoConfirmationDataType: base(sa:SubjectConfirmationDataType) ds:KeyInfo+ ; Conditions -> %sa:ConditionsType %ConditionsType: sa:Condition* # *** Stated differently in XSD sa:AudienceRestriction* sa:OneTimeUse* sa:ProxyRestriction* idp:SubjectRestriction* @NotBefore? -> %xs:dateTime @NotOnOrAfter? -> %xs:dateTime ; Condition -> %sa:ConditionAbstractType AudienceRestriction -> %sa:AudienceRestrictionType %AudienceRestrictionType: base(sa:ConditionAbstractType) sa:Audience+ ; Audience -> %xs:anyURI OneTimeUse -> %sa:OneTimeUseType %OneTimeUseType: base(sa:ConditionAbstractType) ; ProxyRestriction -> %sa:ProxyRestrictionType %ProxyRestrictionType: base(sa:ConditionAbstractType) sa:Audience* @Count? -> %xs:nonNegativeInteger ; Advice -> %sa:AdviceType %AdviceType: sa:AssertionIDRef* # *** really a choice, but maxOccurs="unbounded" sa:AssertionURIRef* sa:Assertion* sa:EncryptedAssertion* sa11:Assertion* ff12:Assertion* any* ns(##other) processContents(lax) ; EncryptedAssertion -> %sa:EncryptedElementType Statement -> %sa:StatementAbstractType AuthnStatement -> %sa:AuthnStatementType %AuthnStatementType: base(sa:StatementAbstractType) sa:SubjectLocality? sa:AuthnContext @AuthnInstant -> %xs:dateTime @SessionIndex? -> %xs:string @SessionNotOnOrAfter? -> %xs:dateTime ; SubjectLocality -> %sa:SubjectLocalityType %SubjectLocalityType: @Address? -> %xs:string @DNSName? -> %xs:string ; AuthnContext -> %sa:AuthnContextType %AuthnContextType: sa:AuthnContextClassRef? # N.B. We diverge from canonical XSD sa:AuthnContextDecl? sa:AuthnContextDeclRef? sa:AuthenticatingAuthority* ; AuthnContextClassRef -> %xs:anyURI AuthnContextDeclRef -> %xs:anyURI AuthnContextDecl -> %xs:anyType AuthenticatingAuthority -> %xs:anyURI AuthzDecisionStatement -> %sa:AuthzDecisionStatementType %AuthzDecisionStatementType: base(sa:StatementAbstractType) sa:Action+ sa:Evidence? @Decision -> %sa:DecisionType @Resource -> %xs:anyURI ; %DecisionType: enum( Permit Deny Indeterminate ) ; Action -> %sa:ActionType %ActionType: base(string) @Namespace -> %xs:anyURI ; Evidence -> %sa:EvidenceType %EvidenceType: sa:AssertionIDRef* # XSD has choice maxOccurs="unbounded" sa:AssertionURIRef* sa:Assertion* sa:EncryptedAssertion* ; AttributeStatement -> %sa:AttributeStatementType %AttributeStatementType: base(sa:StatementAbstractType) sa:Attribute* # XSD has choice maxOccurs="unbounded" sa:EncryptedAttribute* ; Attribute -> %sa:AttributeType %AttributeType: sa:AttributeValue* @FriendlyName? -> %xs:string @Name -> %xs:string @NameFormat? -> %xs:anyURI @any ; # To cater for discovery bootstraps we add them to schema here #AttributeValue -> %xs:anyType AttributeValue -> %sa:AttributeValueType %AttributeValueType: di12:ResourceOffering* a:EndpointReference* ; EncryptedAttribute -> %sa:EncryptedElementType TestElem: sa:AttributeValue* ; #EOF
# zxid/sg/saml-schema-protocol-2.0.sg # $Id: saml-schema-protocol-2.0.sg,v 1.5 2008-02-23 03:59:31 sampo Exp $ # # N.B. This file is not a direct conversion. Instead it has been manually # edited to make it simpler and to facilitate code generation. target(sp,urn:oasis:names:tc:SAML:2.0:protocol) import(sa,urn:oasis:names:tc:SAML:2.0:assertion,saml-schema-assertion-2.0.xsd) import(ds,http://www.w3.org/2000/09/xmldsig#,http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd) ns(xs, http://www.w3.org/2001/XMLSchema) %RequestAbstractType: sa:Issuer? ds:Signature? sp:Extensions? @ID -> %xs:ID @Version -> %xs:string @IssueInstant -> %xs:dateTime @Destination? -> %xs:anyURI @Consent? -> %xs:anyURI ; Extensions -> %sp:ExtensionsType %ExtensionsType: any+ ; %StatusResponseType: sa:Issuer? ds:Signature? sp:Extensions? sp:Status @ID -> %xs:ID @InResponseTo? -> %xs:NCName @Version -> %xs:string @IssueInstant -> %xs:dateTime @Destination? -> %xs:anyURI @Consent? -> %xs:anyURI ; Status -> %sp:StatusType %StatusType: sp:StatusCode sp:StatusMessage? sp:StatusDetail? ; StatusCode -> %sp:StatusCodeType %StatusCodeType: sp:StatusCode? @Value -> %xs:anyURI ; StatusMessage -> %xs:string StatusDetail -> %sp:StatusDetailType %StatusDetailType: any* ; AssertionIDRequest -> %sp:AssertionIDRequestType %AssertionIDRequestType: base(sp:RequestAbstractType) sa:AssertionIDRef+ ; SubjectQuery -> %sp:SubjectQueryAbstractType %SubjectQueryAbstractType: base(sp:RequestAbstractType) sa:Subject ; AuthnQuery -> %sp:AuthnQueryType %AuthnQueryType: base(sp:SubjectQueryAbstractType) sp:RequestedAuthnContext? @SessionIndex? -> %xs:string ; RequestedAuthnContext -> %sp:RequestedAuthnContextType %RequestedAuthnContextType: sa:AuthnContextClassRef* sa:AuthnContextDeclRef* @Comparison? -> %sp:AuthnContextComparisonType ; %AuthnContextComparisonType: enum( exact minimum maximum better ) ; AttributeQuery -> %sp:AttributeQueryType %AttributeQueryType: base(sp:SubjectQueryAbstractType) sa:Attribute* ; AuthzDecisionQuery -> %sp:AuthzDecisionQueryType %AuthzDecisionQueryType: base(sp:SubjectQueryAbstractType) sa:Action+ sa:Evidence? @Resource -> %xs:anyURI ; AuthnRequest -> %sp:AuthnRequestType %AuthnRequestType: base(sp:RequestAbstractType) sa:Subject? sp:NameIDPolicy? sa:Conditions? sp:RequestedAuthnContext? sp:Scoping? @ForceAuthn? -> %xs:boolean @IsPassive? -> %xs:boolean @ProtocolBinding? -> %xs:anyURI @AssertionConsumerServiceIndex? -> %xs:unsignedShort @AssertionConsumerServiceURL? -> %xs:anyURI @AttributeConsumingServiceIndex? -> %xs:unsignedShort @ProviderName? -> %xs:string ; NameIDPolicy -> %sp:NameIDPolicyType %NameIDPolicyType: @Format? -> %xs:anyURI @SPNameQualifier? -> %xs:string @AllowCreate? -> %xs:boolean ; Scoping -> %sp:ScopingType %ScopingType: sp:IDPList? sp:RequesterID* @ProxyCount? -> %xs:nonNegativeInteger ; RequesterID -> %xs:anyURI IDPList -> %sp:IDPListType %IDPListType: sp:IDPEntry+ sp:GetComplete? ; IDPEntry -> %sp:IDPEntryType %IDPEntryType: @ProviderID -> %xs:anyURI @Name? -> %xs:string @Loc? -> %xs:anyURI ; GetComplete -> %xs:anyURI Response -> %sp:ResponseType %ResponseType: base(sp:StatusResponseType) sa:Assertion? sa:EncryptedAssertion? ; ArtifactResolve -> %sp:ArtifactResolveType %ArtifactResolveType: base(sp:RequestAbstractType) sp:Artifact ; Artifact -> %xs:string ArtifactResponse -> %sp:ArtifactResponseType %ArtifactResponseType: base(sp:StatusResponseType) sp:Response? any? ; ManageNameIDRequest -> %sp:ManageNameIDRequestType %ManageNameIDRequestType: base(sp:RequestAbstractType) sa:NameID? sa:EncryptedID? sp:NewID? sp:NewEncryptedID? sp:Terminate? ; NewID -> %xs:string NewEncryptedID -> %sa:EncryptedElementType Terminate -> %sp:TerminateType ManageNameIDResponse -> %sp:StatusResponseType LogoutRequest -> %sp:LogoutRequestType %LogoutRequestType: base(sp:RequestAbstractType) sa:BaseID? sa:NameID? sa:EncryptedID? sp:SessionIndex* @Reason? -> %xs:string @NotOnOrAfter? -> %xs:dateTime ; SessionIndex -> %xs:string LogoutResponse -> %sp:StatusResponseType NameIDMappingRequest -> %sp:NameIDMappingRequestType %NameIDMappingRequestType: base(sp:RequestAbstractType) sa:BaseID? sa:NameID? sa:EncryptedID? sp:NameIDPolicy ; NameIDMappingResponse -> %sp:NameIDMappingResponseType %NameIDMappingResponseType: base(sp:StatusResponseType) sa:NameID? sa:EncryptedID? ; #EOF
# zxid/sg/saml-schema-metadata-2.0.sh .sg
# Slightly edited, 27.5.2006, Sampo Kellomaki (sampo@iki.fi)
# $Id: saml-schema-metadata-2.0.sg,v 1.3 2007-10-09 16:56:13 sampo Exp $
target(md,urn:oasis:names:tc:SAML:2.0:metadata)
import(ds,http://www.w3.org/2000/09/xmldsig#,http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd)
import(xenc,http://www.w3.org/2001/04/xmlenc#,http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd)
import(sa,urn:oasis:names:tc:SAML:2.0:assertion,saml-schema-assertion-2.0.xsd)
# import(xml,http://www.w3.org/XML/1998/namespace,http://www.w3.org/2001/xml.xsd)
ns(xs, http://www.w3.org/2001/XMLSchema)
ns(xml, http://www.w3.org/XML/1998/namespace)
%entityIDType: base(xs:anyURI) ;
%localizedNameType: base(xs:string)
@xml:lang? -> %xs:string #@xml:lang vs. @lang ***
#@lang? -> %xs:string
;
%localizedURIType: base(xs:anyURI)
@xml:lang? -> %xs:string #@xml:lang vs. @lang ***
#@lang? -> %xs:string
;
Extensions -> %md:ExtensionsType
%ExtensionsType:
any+
;
%EndpointType:
any*
@Binding -> %xs:anyURI
@Location -> %xs:anyURI
@ResponseLocation? -> %xs:anyURI
@index? -> %xs:unsignedShort
@isDefault? -> %xs:boolean
@any
;
EntitiesDescriptor -> %md:EntitiesDescriptorType
%EntitiesDescriptorType:
ds:Signature?
md:Extensions?
md:EntityDescriptor* # these were originally choice unbounded
md:EntitiesDescriptor*
@validUntil? -> %dateTime
@cacheDuration? -> %duration
@ID? -> %xs:ID
@Name? -> %xs:string
;
EntityDescriptor -> %md:EntityDescriptorType
%EntityDescriptorType:
ds:Signature?
md:Extensions?
md:RoleDescriptor* # following were originally choice unbounded
md:IDPSSODescriptor*
md:SPSSODescriptor*
md:AuthnAuthorityDescriptor*
md:AttributeAuthorityDescriptor*
md:PDPDescriptor*
md:AffiliationDescriptor*
md:Organization?
md:ContactPerson*
md:AdditionalMetadataLocation*
@entityID -> %md:entityIDType
@validUntil? -> %dateTime
@cacheDuration? -> %duration
@ID? -> %xs:ID
@any
;
Organization -> %md:OrganizationType
%OrganizationType:
md:Extensions?
md:OrganizationName+
md:OrganizationDisplayName+
md:OrganizationURL+
@any
;
OrganizationName -> %md:localizedNameType
OrganizationDisplayName -> %md:localizedNameType
OrganizationURL -> %md:localizedURIType
ContactPerson -> %md:ContactType
%ContactType:
md:Extensions?
md:Company?
md:GivenName?
md:SurName?
md:EmailAddress*
md:TelephoneNumber*
@contactType -> %md:ContactTypeType
@any
;
Company -> %xs:string
GivenName -> %xs:string
SurName -> %xs:string
EmailAddress -> %xs:anyURI
TelephoneNumber -> %xs:string
%ContactTypeType: enum( technical support administrative billing other ) ;
AdditionalMetadataLocation -> %md:AdditionalMetadataLocationType
%AdditionalMetadataLocationType: base(xs:anyURI)
@namespace -> %xs:anyURI
;
RoleDescriptor -> %md:RoleDescriptorType
%RoleDescriptorType:
ds:Signature?
md:Extensions?
md:KeyDescriptor*
md:Organization?
md:ContactPerson*
@ID? -> %xs:ID
@validUntil? -> %dateTime
@cacheDuration? -> %duration
@protocolSupportEnumeration -> %xs:anyURI
@errorURL? -> %xs:anyURI
@any
;
KeyDescriptor -> %md:KeyDescriptorType
%KeyDescriptorType:
ds:KeyInfo
md:EncryptionMethod*
@use? -> %md:KeyTypes
;
%KeyTypes: enum( encryption signing ) ;
EncryptionMethod -> %xenc:EncryptionMethodType
%SSODescriptorType: base(md:RoleDescriptorType)
md:ArtifactResolutionService*
md:SingleLogoutService*
md:ManageNameIDService*
md:NameIDFormat*
;
ArtifactResolutionService -> %md:EndpointType
SingleLogoutService -> %md:EndpointType
ManageNameIDService -> %md:EndpointType
NameIDFormat -> %xs:anyURI
IDPSSODescriptor -> %md:IDPSSODescriptorType
%IDPSSODescriptorType: base(md:SSODescriptorType)
md:SingleSignOnService+
md:NameIDMappingService*
md:AssertionIDRequestService*
md:AttributeProfile*
sa:Attribute*
@WantAuthnRequestsSigned? -> %xs:boolean
;
SingleSignOnService -> %md:EndpointType
NameIDMappingService -> %md:EndpointType
AssertionIDRequestService -> %md:EndpointType
AttributeProfile -> %xs:anyURI
SPSSODescriptor -> %md:SPSSODescriptorType
%SPSSODescriptorType: base(md:SSODescriptorType)
md:AssertionConsumerService+
md:AttributeConsumingService*
@AuthnRequestsSigned? -> %xs:boolean
@WantAssertionsSigned? -> %xs:boolean
;
AssertionConsumerService -> %md:EndpointType
AttributeConsumingService -> %md:AttributeConsumingServiceType
%AttributeConsumingServiceType:
md:ServiceName+
md:ServiceDescription*
md:RequestedAttribute+
@index -> %xs:unsignedShort
@isDefault? -> %xs:boolean
;
ServiceName -> %md:localizedNameType
ServiceDescription -> %md:localizedNameType
RequestedAttribute -> %md:RequestedAttributeType
%RequestedAttributeType: base(sa:AttributeType)
@isRequired? -> %xs:boolean
;
AuthnAuthorityDescriptor -> %md:AuthnAuthorityDescriptorType
%AuthnAuthorityDescriptorType: base(md:RoleDescriptorType)
md:AuthnQueryService+
md:AssertionIDRequestService*
md:NameIDFormat*
;
AuthnQueryService -> %md:EndpointType
PDPDescriptor -> %md:PDPDescriptorType
%PDPDescriptorType: base(md:RoleDescriptorType)
md:AuthzService+
md:AssertionIDRequestService*
md:NameIDFormat*
;
AuthzService -> %md:EndpointType
AttributeAuthorityDescriptor -> %md:AttributeAuthorityDescriptorType
%AttributeAuthorityDescriptorType: base(md:RoleDescriptorType)
md:AttributeService+
md:AssertionIDRequestService*
md:NameIDFormat*
md:AttributeProfile*
sa:Attribute*
;
AttributeService -> %md:EndpointType
AffiliationDescriptor -> %md:AffiliationDescriptorType
%AffiliationDescriptorType:
ds:Signature?
md:Extensions?
md:AffiliateMember+
md:KeyDescriptor*
@affiliationOwnerID -> %md:entityIDType
@validUntil? -> %dateTime
@cacheDuration? -> %duration
@ID? -> %xs:ID
@any
;
AffiliateMember -> %md:entityIDType
#EOF
# zxid/sg/liberty-idwsf-utility-v2.0.sg # Slightly edited, 18.9.2006, Sampo Kellomaki (sampo@iki.fi) # $Id: liberty-idwsf-utility-v2.0.sg,v 1.2 2006/09/15 05:56:49 sampo Exp $ target(lu, urn:liberty:util:2006-08) %IDType: base(xs:string) ; %IDReferenceType: base(xs:string) ; @itemID -> %lu:IDType @itemIDRef -> %lu:IDReferenceType %StatusType: lu:Status* @code -> %xs:string @ref? -> %lu:IDReferenceType @comment? -> %xs:string ; Status -> %lu:StatusType %ResponseType: lu:Status lu:Extension* @itemIDRef? -> %lu:IDReferenceType @any ; TestResult -> %lu:TestResultType %TestResultType: base(xs:boolean) @itemIDRef -> %lu:IDReferenceType ; %EmptyType: base(xs:anyType) ; Extension -> %lu:extensionType %extensionType: any+ ns(##other) processContents(lax) ; #EOF
# zxid/sg/liberty-idwsf-soap-binding-v2.0.sg # Slightly edited, 5.9.2006, Sampo Kellomaki (sampo@iki.fi) # $Id: liberty-idwsf-soap-binding-v2.0.sg,v 1.7 2007-09-30 05:10:03 sampo Exp $ target(b, urn:liberty:sb:2006-08) import(sp, urn:oasis:names:tc:SAML:2.0:protocol) import(wsu, http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd,wss-util-1.0.xsd) import(a, http://www.w3.org/2005/08/addressing,ws-addr-1.0.xsd) import(lu, urn:liberty:util:2006-08,liberty-idwsf-utility-v2.0.xsd) import(e, http://schemas.xmlsoap.org/soap/envelope/) import(sa11, urn:oasis:names:tc:SAML:1.0:assertion) import(sa, urn:oasis:names:tc:SAML:2.0:assertion) import(ff12, urn:liberty:iff:2003-08) &@hdr: @wsu:Id? @e:mustUnderstand? @e:actor? @id? -> %xs:anyURI ; Framework -> %b:FrameworkType %FrameworkType: any* processContents(lax) @version -> %xs:string &@b:hdr # Added by Sampo @any ; Sender -> %b:SenderType %SenderType: @providerID -> %xs:anyURI @affiliationID? -> %xs:anyURI &@b:hdr # Added by Sampo @any ; TargetIdentity -> %b:TargetIdentityType %TargetIdentityType: sa:Assertion? sa11:Assertion? ff12:Assertion? any* processContents(lax) &@b:hdr # Added by Sampo @any ; CredentialsContext -> %b:CredentialsContextType %CredentialsContextType: sp:RequestedAuthnContext? b:SecurityMechID* -> %xs:anyURI &@b:hdr # Added by Sampo @any ; EndpointUpdate -> %b:EndpointUpdateType %EndpointUpdateType: base(a:EndpointReferenceType) @updateType? -> %xs:anyURI ; Timeout -> %b:TimeoutType %TimeoutType: @maxProcessingTime -> %xs:integer &@b:hdr # Added by Sampo @any ; ProcessingContext -> %b:ProcessingContextType %ProcessingContextType: base(xs:anyURI) &@b:hdr # Added by Sampo @any ; Consent -> %b:ConsentType %ConsentType: @uri -> %xs:anyURI @timestamp? -> %xs:dateTime &@b:hdr # Added by Sampo @any ; UsageDirective -> %b:UsageDirectiveType %UsageDirectiveType: any+ ns(##other) processContents(lax) @ref -> %xs:IDREF &@b:hdr # Added by Sampo @any ; ApplicationEPR -> %a:EndpointReferenceType UserInteraction -> %b:UserInteractionHeaderType %UserInteractionHeaderType: b:InteractionService* -> %a:EndpointReferenceType @interact? -> %xs:string default (interactIfNeeded) @language? -> %xs:NMTOKENS @redirect? -> %xs:boolean default (0) @maxInteractTime? -> %xs:integer &@b:hdr # Added by Sampo @any ; RedirectRequest -> %b:RedirectRequestType %RedirectRequestType: @redirectURL -> %xs:anyURI &@b:hdr # Added by Sampo ; #EOF
# zxid/sg/liberty-idwsf-security-mechanisms-v2.0.sg # Slightly edited, 5.9.2006, Sampo Kellomaki (sampo@iki.fi) # 10.2.2007, added sa:Assertion as potential security token type --Sampo # $Id: liberty-idwsf-security-mechanisms-v2.0.sg,v 1.5 2007-09-28 19:57:43 sampo Exp $ target(sec, urn:liberty:security:2006-08) ns(sa, urn:oasis:names:tc:SAML:2.0:assertion) ns(sa11, urn:oasis:names:tc:SAML:1.0:assertion) ns(ff12, urn:liberty:iff:2003-08) TokenPolicy -> %sec:TokenPolicyType %TokenPolicyType: any? processContents(lax) @validUntil? -> %xs:dateTime @issueTo? -> %xs:anyURI @type? -> %xs:anyURI @wantDSEPR? -> %xs:boolean @any ; TransitedProvider -> %sec:TransitedProviderType %TransitedProviderType: base(xs:anyURI) @timeStamp? -> %xs:dateTime @confirmationURI? -> %xs:anyURI ; TransitedProviderPath -> %sec:TransitedProviderPathType %TransitedProviderPathType: sec:TransitedProvider+ ; Token -> %sec:TokenType %TokenType: sa:Assertion? sa:EncryptedAssertion? sa11:Assertion? ff12:Assertion? any* processContents(lax) @id? -> %xs:ID @ref? -> %xs:anyURI @usage? -> %xs:anyURI ; #EOF
# zxid/sg/liberty-idwsf-disco-svc-v2.0.sg # Slightly edited, 18.9.2006, Sampo Kellomaki (sampo@iki.fi) # $Id: liberty-idwsf-disco-svc-v2.0.sg,v 1.1 2006/09/15 04:44:47 sampo Exp $ target(di, urn:liberty:disco:2006-08) import(md, urn:oasis:names:tc:SAML:2.0:metadata, saml-schema-metadata-2.0.xsd) import(b, urn:liberty:sb:2006-08, liberty-idwsf-soap-binding-v2.0.xsd) import(sbf, urn:liberty:sb, liberty-idwsf-soap-binding.xsd) import(a, http://www.w3.org/2005/08/addressing, ws-addr-1.0.xsd) import(lu, urn:liberty:util:2006-08, liberty-idwsf-utility-v2.0.xsd) import(sec, urn:liberty:security:2006-08, liberty-idwsf-security-mechanisms-v2.0.xsd) Abstract -> %xs:string ProviderID -> %xs:anyURI ServiceType -> %xs:anyURI Framework -> %sbf:FrameworkType @NotOnOrAfter -> %xs:dateTime SecurityContext: di:SecurityMechID+ sec:Token* ; SecurityMechID -> %xs:anyURI Options -> %di:OptionsType Option -> %xs:anyURI %OptionsType: di:Option* ; Address -> %xs:anyURI Action -> %xs:anyURI Keys -> %di:KeysType %KeysType: md:KeyDescriptor+ ; SvcMD -> %di:SvcMetadataType %SvcMetadataType: di:Abstract di:ProviderID di:ServiceContext+ @svcMDID? -> %xs:string ; ServiceContext -> %di:ServiceContextType %ServiceContextType: di:ServiceType+ di:Options* di:EndpointContext+ ; EndpointContext -> %di:EndpointContextType %EndpointContextType: di:Address+ sbf:Framework+ di:SecurityMechID+ di:Action* ; SvcMDID -> %xs:string Query -> %di:QueryType %QueryType: di:RequestedService* -> %di:RequestedServiceType @any ; %RequestedServiceType: di:ServiceType* di:ProviderID* di:Options* di:SecurityMechID* di:Framework* di:Action* any* ns(##other) processContents(lax) @reqID? -> %xs:string @resultsType? -> %xs:string ; QueryResponse -> %di:QueryResponseType %QueryResponseType: lu:Status a:EndpointReference* @any ; SvcMDAssociationAdd -> %di:SvcMDAssociationAddType %SvcMDAssociationAddType: di:SvcMDID+ @any ; SvcMDAssociationAddResponse -> %di:SvcMDAssociationAddResponseType %SvcMDAssociationAddResponseType: lu:Status @any ; SvcMDAssociationDelete -> %di:SvcMDAssociationDeleteType %SvcMDAssociationDeleteType: di:SvcMDID+ @any ; SvcMDAssociationDeleteResponse -> %di:SvcMDAssociationDeleteResponseType %SvcMDAssociationDeleteResponseType: lu:Status @any ; SvcMDAssociationQuery -> %di:SvcMDAssociationQueryType %SvcMDAssociationQueryType: di:SvcMDID* @any ; SvcMDAssociationQueryResponse -> %di:SvcMDAssociationQueryResponseType %SvcMDAssociationQueryResponseType: lu:Status di:SvcMDID* @any ; SvcMDRegister -> %di:SvcMDRegisterType %SvcMDRegisterType: di:SvcMD+ @any ; SvcMDRegisterResponse -> %di:SvcMDRegisterResponseType %SvcMDRegisterResponseType: lu:Status di:SvcMDID* di:Keys* @any ; SvcMDDelete -> %di:SvcMDDeleteType %SvcMDDeleteType: di:SvcMDID+ @any ; SvcMDDeleteResponse -> %di:SvcMDDeleteResponseType %SvcMDDeleteResponseType: lu:Status @any ; SvcMDQuery -> %di:SvcMDQueryType %SvcMDQueryType: di:SvcMDID* @any ; SvcMDQueryResponse -> %di:SvcMDQueryResponseType %SvcMDQueryResponseType: lu:Status di:SvcMD* @any ; SvcMDReplace -> %di:SvcMDReplaceType %SvcMDReplaceType: di:SvcMD+ @any ; SvcMDReplaceResponse -> %di:SvcMDReplaceResponseType %SvcMDReplaceResponseType: lu:Status @any ; #EOF
# id-dap.sg -- Authorative ID-DAP 1.0 Service Schema
# Author: Sampo Kellomaki (sampo@symlabs.com)
# http://www.w3.org/2001/03/webdata/xsv
# $Id: id-dap.sg,v 1.2 2007-06-19 15:17:04 sampo Exp $
# This schema reflects Liberty ID Directory Access Protocol,
# version 1.0-07 of 11.10.2006
target(dap, urn:liberty:id-sis-dap:2006-08:dst-2.1)
import(dst, urn:liberty:dst:2006-08, liberty-idwsf-dst-v2.1.xsd)
import(subs, urn:liberty:ssos:2006-08, liberty-idwsf-subs-v1.0.xsd)
import(lu, urn:liberty:util:2006-08, liberty-idwsf-utility-v2.0.xsd)
Create -> %dap:CreateType
CreateResponse -> %dap:CreateResponseType
Query -> %dap:QueryType
QueryResponse -> %dap:QueryResponseType
Modify -> %dap:ModifyType
ModifyResponse -> %dap:ModifyResponseType
Delete -> %dap:DeleteType
DeleteResponse -> %dap:DeleteResponseType
Notify -> %dap:NotifyType
NotifyResponse -> %dap:NotifyResponseType
%SelectType:
dap:dn? -> %xs:string
dap:filter? -> %xs:string
@scope? -> %xs:integer default(0)
@sizelimit? -> %xs:integer default(0)
@timelimit? -> %xs:integer default(0)
@attributes? -> %xs:string
@typesonly? -> %xs:boolean default(false)
@derefaliases? -> %xs:integer default(0)
;
%TestOpType: base(dap:SelectType) ;
%SortType: base(xs:string) ;
%TriggerType: base(xs:string) ;
%AggregationType: base(xs:string) ;
%AppDataType:
dap:LDIF?
dap:Subscription?
;
LDIF: base(xs:string)
&@dst:localizedLeafAttributes
;
%CreateType: base(dst:RequestType)
dap:Subscription*
dap:CreateItem+
dap:ResultQuery*
;
CreateItem -> %dap:CreateItemType
%CreateItemType:
dap:NewData?
&@dst:CreateItemAttributeGroup
;
NewData -> %dap:AppDataType
%CreateResponseType: base(dap:DataResponseType) ;
%DataResponseType: base(dst:DataResponseBaseType)
dap:ItemData*
;
%QueryType: base(dst:RequestType)
dap:TestItem*
dap:QueryItem*
dap:Subscription*
;
TestItem -> %dap:TestItemType
%TestItemType: base(dst:TestItemBaseType)
dap:TestOp? -> %dap:TestOpType
;
QueryItem -> %dap:QueryItemType
%QueryItemType: base(dap:ResultQueryType)
&@dst:PaginationAttributeGroup
;
%QueryResponseType: base(dst:DataResponseBaseType)
dst:TestResult*
dap:Data*
;
Data -> %dap:DataType
%DataType: base(dap:ItemDataType)
&@dst:PaginationResponseAttributeGroup
;
%ModifyType: base(dst:RequestType)
dap:Subscription*
dap:ModifyItem+
dap:ResultQuery*
;
ModifyItem -> %dap:ModifyItemType
%ModifyItemType:
dap:Select?
dap:NewData?
&@dst:ModifyItemAttributeGroup
;
%ModifyResponseType: base(dap:DataResponseType) ;
%DeleteType: base(dst:RequestType)
dap:DeleteItem+
;
DeleteItem -> %dap:DeleteItemType
%DeleteItemType: base(dst:DeleteItemBaseType)
dap:Select?
;
%DeleteResponseType: base(lu:ResponseType) ;
Select -> %dap:SelectType
ResultQuery -> %dap:ResultQueryType
%ResultQueryType: base(dst:ResultQueryBaseType)
dap:Select?
dap:Sort? -> %dap:SortType
;
ItemData -> %dap:ItemDataType
%ItemDataType: base(dap:AppDataType)
&@dst:ItemDataAttributeGroup
;
Subscription -> %dap:SubscriptionType
%SubscriptionType: base(subs:SubscriptionType)
dap:ResultQuery*
dap:Aggregation? -> %dap:AggregationType
dap:Trigger? -> %dap:TriggerType
;
%NotifyType: base(dst:RequestType)
dap:Notification*
&@subs:NotifyAttributeGroup
;
Notification -> %dap:NotificationType
%NotificationType: base(subs:NotificationType)
dap:ItemData*
;
%NotifyResponseType: base(subs:NotifyResponseType) ;
#EOF
# zxid/sg/liberty-idwsf-subs-v1.0.sg # Slightly edited, 1.3.2007, Sampo Kellomaki (sampo@iki.fi) # $Id: liberty-idwsf-subs-v1.0.sg,v 1.1 2007/03/04 08:24:58 sampo Exp $ target(subs, urn:liberty:ssos:2006-08) import(lu, urn:liberty:util:2006-08,liberty-idwsf-utility-v2.0.xsd) %SubscriptionType: subs:RefItem* lu:Extension* @subscriptionID -> %lu:IDType @notifyToRef -> %xs:anyURI @adminNotifyToRef? -> %xs:anyURI @starts? -> %xs:dateTime @expires? -> %xs:dateTime @id? -> %xs:ID @includeData?: enum( Yes No YesWithCommonAttributes ) ; ; RefItem -> %subs:RefItemType %RefItemType: @subscriptionID? -> %lu:IDType @lu:itemIDRef ; &@NotifyAttributeGroup: @timeStamp? -> %xs:dateTime ; %NotificationType: lu:TestResult* @id? -> %xs:ID @subscriptionID -> %lu:IDType @expires? -> %xs:dateTime @endReason? -> %xs:anyURI ; %NotifyResponseType: base(lu:ResponseType) ; #EOF
# zxid/sg/liberty-idwsf-dst-v2.1.sg
# Slightly edited, 1.3.2007, Sampo Kellomaki (sampo@iki.fi)
# $Id: liberty-idwsf-dst-v2.1.sg,v 1.1 2007/03/04 08:24:58 sampo Exp $
target(dst, urn:liberty:dst:2006-08)
import(lu, urn:liberty:util:2006-08, liberty-idwsf-utility-v2.0.xsd)
import(xml, http://www.w3.org/XML/1998/namespace, http://www.w3.org/2001/xml.xsd)
@id -> %lu:IDType
@modificationTime -> %xs:dateTime
&@commonAttributes:
@dst:id?
@dst:modificationTime?
;
@ACC -> %xs:anyURI
@ACCTime -> %xs:dateTime
@modifier -> %xs:string
&@leafAttributes:
&@dst:commonAttributes
@dst:ACC?
@dst:ACCTime?
@dst:modifier?
;
@script -> %xs:anyURI
&@localizedLeafAttributes:
&@dst:leafAttributes
@xml:lang
@dst:script?
;
@refreshOnOrAfter -> %xs:dateTime
@destroyOnOrAfter -> %xs:dateTime
%DSTLocalizedString: base(xs:string)
&@dst:localizedLeafAttributes
;
%DSTString: base(xs:string)
&@dst:leafAttributes
;
%DSTInteger: base(xs:integer)
&@dst:leafAttributes
;
%DSTURI: base(xs:anyURI)
&@dst:leafAttributes
;
%DSTDate: base(xs:date)
&@dst:leafAttributes
;
%DSTMonthDay: base(xs:gMonthDay)
&@dst:leafAttributes
;
@itemID -> %lu:IDType
@itemIDRef -> %lu:IDReferenceType
%RequestType:
lu:Extension*
@dst:itemID?
@any
;
%ResponseType:
lu:Status
lu:Extension*
@dst:itemIDRef?
@any
;
%DataResponseBaseType: base(dst:ResponseType)
@timeStamp? -> %xs:dateTime
;
ChangeFormat: enum( ChangedElements CurrentElements ) ;
@changeFormat: enum( ChangedElements CurrentElements All ) ;
@objectType -> %xs:NCName
@predefined -> %xs:string
&@selectQualif:
@dst:objectType?
@dst:predefined?
;
%ResultQueryBaseType:
dst:ChangeFormat{0,2}
&@dst:selectQualif
@dst:itemIDRef?
@contingency? -> %xs:boolean
@includeCommonAttributes? -> %xs:boolean default (0)
@changedSince? -> %xs:dateTime
@dst:itemID?
;
&@ItemDataAttributeGroup:
@dst:itemIDRef?
@notSorted?: enum( Now Never ) ;
@dst:changeFormat?
;
%TestItemBaseType:
&@dst:selectQualif
@id? -> %xs:ID
@dst:itemID?
;
TestResult -> %dst:TestResultType
%TestResultType: base(xs:boolean)
@dst:itemIDRef
;
&@PaginationAttributeGroup:
@count? -> %xs:nonNegativeInteger
@offset? -> %xs:nonNegativeInteger default (0)
@setID? -> %lu:IDType
@setReq?: enum( Static DeleteSet ) ;
;
&@PaginationResponseAttributeGroup:
@remaining? -> %xs:integer
@nextOffset? -> %xs:nonNegativeInteger default (0)
@setID? -> %lu:IDType
;
&@CreateItemAttributeGroup:
@dst:objectType?
@id? -> %xs:ID
@dst:itemID?
;
&@ModifyItemAttributeGroup:
&@dst:selectQualif
@notChangedSince? -> %xs:dateTime
@overrideAllowed? -> %xs:boolean default (0)
@id? -> %xs:ID
@dst:itemID?
;
%DeleteItemBaseType:
&@dst:selectQualif
@notChangedSince? -> %xs:dateTime
@id? -> %xs:ID
@dst:itemID?
;
%DeleteResponseType: base(dst:ResponseType) ;
#EOF
# zxid/sg/wsf-soap11.sg # $Id: wsf-soap11.sg,v 1.11 2007-10-05 22:24:28 sampo Exp $ # Heavily edited, 27.5.2006, Sampo Kellomaki (sampo@iki.fi) # 26.2.2007, merged saml20-soap11.sg and di-soap11.sg to only # one SOAP processor. --Sampo # 3.3.2007, added XACML support --Sampo # # Mega SOAP processor for Web Services and SSO Frameworks # # Main purpose of this schema is to permit direct, one pass, parsing of # of SAML and WSF content in SOAP envelope. Thus relevant SOAP extension # points have been replaced with actual SAML and WSF elements. # # When you add new SOAP messages, you need to add them here, to the body. target(e, http://schemas.xmlsoap.org/soap/envelope/) ns(xs, http://www.w3.org/2001/XMLSchema) ns(a, http://www.w3.org/2005/08/addressing) ns(sbf, urn:liberty:sb) ns(b, urn:liberty:sb:2006-08) ns(b12, urn:liberty:sb:2003-08) ns(di, urn:liberty:disco:2006-08) ns(di12, urn:liberty:disco:2003-08) ns(dap, urn:liberty:id-sis-dap:2006-08:dst-2.1) ns(ps, urn:liberty:ps:2006-08) ns(im, urn:liberty:ims:2006-08) ns(as, urn:liberty:sa:2006-08) ns(wsse, http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd) ns(xasp, urn:oasis:xacml:2.0:saml:protocol:schema:os) ns(mm7, http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-4) ns(cb, urn:liberty:id-sis-cb:2004-10) ns(gl, urn:liberty:id-sis-gl:2005-07) ns(dp, urn:liberty:dp:2006-12) ns(pmm, urn:liberty:pmm:2006-12) ns(prov, urn:liberty:prov:2006-12) ns(shps, urn:liberty:shps:2006-12) ns(idp, urn:liberty:idp:2006-12) ns(idhrxml, urn:id-sis-idhrxml:2007-06:dst-2.1) ns(demomed, urn:x-demo:me:2006-01) Envelope -> %e:Envelope %Envelope: e:Header? e:Body @id? -> %xs:ID any* @any? ; Header -> %e:Header %Header: paos:Request? paos:Response? ecp:Request? ecp:Response? ecp:RelayState? a:MessageID? a:RelatesTo? a:ReplyTo? a:From? a:FaultTo? a:To? a:Action? a:ReferenceParameters? sbf:Framework? b:Framework? b:Sender? b:TargetIdentity? b:CredentialsContext? b:EndpointUpdate? b:Timeout? b:ProcessingContext? b:Consent? b:UsageDirective? b:ApplicationEPR? b:UserInteraction? b:RedirectRequest? b12:Correlation? b12:Provider? b12:ProcessingContext? b12:Consent? b12:UsageDirective? mm7:TransactionID? wsse:Security? @id? -> %xs:ID any* @any? ; Body -> %e:Body %Body: sp:ArtifactResolve? sp:ArtifactResponse? sp:ManageNameIDRequest? sp:ManageNameIDResponse? sp:LogoutRequest? sp:LogoutResponse? sp:NameIDMappingRequest? sp:NameIDMappingResponse? sp:AttributeQuery? sp:AuthnQuery? sp:AuthzDecisionQuery? sp:AssertionIDRequest? sp:Response? sp:AuthnRequest? sp11:Request? sp11:Response? ff12:RegisterNameIdentifierRequest? ff12:RegisterNameIdentifierResponse? ff12:FederationTerminationNotification? ff12:LogoutRequest? ff12:LogoutResponse? ff12:NameIdentifierMappingRequest? ff12:NameIdentifierMappingResponse? xasp:XACMLAuthzDecisionQuery? xasp:XACMLPolicyQuery? di:Query? di:QueryResponse? di12:Query? di12:QueryResponse? di12:Modify? di12:ModifyResponse? e:Fault? di:SvcMDAssociationAdd? di:SvcMDAssociationAddResponse? di:SvcMDAssociationDelete? di:SvcMDAssociationDeleteResponse? di:SvcMDAssociationQuery? di:SvcMDAssociationQueryResponse? di:SvcMDRegister? di:SvcMDRegisterResponse? di:SvcMDDelete? di:SvcMDDeleteResponse? di:SvcMDQuery? di:SvcMDQueryResponse? di:SvcMDReplace? di:SvcMDReplaceResponse? dap:Create? dap:CreateResponse? dap:Query? dap:QueryResponse? dap:Modify? dap:ModifyResponse? dap:Delete? dap:DeleteResponse? dap:Notify? dap:NotifyResponse? ps:AddEntityRequest? ps:AddEntityResponse? ps:AddKnownEntityRequest? ps:AddKnownEntityResponse? ps:AddCollectionRequest? ps:AddCollectionResponse? ps:AddToCollectionRequest? ps:AddToCollectionResponse? ps:RemoveEntityRequest? ps:RemoveEntityResponse? ps:RemoveCollectionRequest? ps:RemoveCollectionResponse? ps:RemoveFromCollectionRequest? ps:RemoveFromCollectionResponse? ps:ListMembersRequest? ps:ListMembersResponse? ps:QueryObjectsRequest? ps:QueryObjectsResponse? ps:GetObjectInfoRequest? ps:GetObjectInfoResponse? ps:SetObjectInfoRequest? ps:SetObjectInfoResponse? ps:TestMembershipRequest? ps:TestMembershipResponse? ps:ResolveIdentifierRequest? ps:ResolveIdentifierResponse? ps:Notify? ps:NotifyResponse? im:IdentityMappingRequest? im:IdentityMappingResponse? as:SASLRequest? as:SASLResponse? mm7:SubmitReq? mm7:SubmitRsp? mm7:DeliverReq? mm7:DeliverRsp? mm7:CancelReq? mm7:CancelRsp? mm7:ReplaceReq? mm7:ReplaceRsp? mm7:extendedCancelReq? mm7:extendedCancelRsp? mm7:extendedReplaceReq? mm7:extendedReplaceRsp? mm7:DeliveryReportReq? mm7:DeliveryReportRsp? mm7:ReadReplyReq? mm7:ReadReplyRsp? mm7:RSErrorRsp? mm7:VASPErrorRsp? mm7:QueryStatusReq? mm7:QueryStatusRsp? cb:Query? cb:QueryResponse? cb:Create? cb:CreateResponse? cb:Delete? cb:DeleteResponse? cb:Modify? cb:ModifyResponse? cb:Notify? cb:NotifyResponse? cb:ReportUsage? cb:ReportUsageResponse? gl:Query? gl:QueryResponse? gl:Create? gl:CreateResponse? gl:Delete? gl:DeleteResponse? gl:Modify? gl:ModifyResponse? gl:Notify? gl:NotifyResponse? demomed:StoreObjectRequest? demomed:StoreObjectResponse? demomed:GetObjectListRequest? demomed:GetObjectListResponse? demomed:GetObjectRequest? demomed:GetObjectResponse? demomed:DeleteObjectRequest? demomed:DeleteObjectResponse? pmm:Provision? pmm:ProvisionResponse? pmm:PMActivate? pmm:PMActivateResponse? pmm:PMDeactivate? pmm:PMDeactivateResponse? pmm:PMDelete? pmm:PMDeleteResponse? pmm:PMUpdate? pmm:PMUpdateResponse? pmm:PMGetStatus? pmm:PMGetStatusResponse? pmm:PMSetStatus? pmm:PMSetStatusResponse? prov:PMERegister? prov:PMERegisterResponse? prov:PMEUpload? prov:PMEUploadResponse? prov:PMEDownload? prov:PMEDownloadResponse? prov:PMEEnable? prov:PMEEnableResponse? prov:PMEDisable? prov:PMEDisableResponse? prov:PMEDelete? prov:PMEDeleteResponse? prov:PMEGetInfo? prov:PMEGetInfoResponse? prov:PMGetStatus? prov:PMGetStatusResponse? prov:PMSetStatus? prov:PMSetStatusResponse? prov:PMGetDescriptor? prov:PMGetDescriptorResponse? prov:PMActivate? prov:PMActivateResponse? prov:PMDeactivate? prov:PMDeactivateResponse? prov:PMRegisterDescriptor? prov:PMRegisterDescriptorResponse? prov:PMUpdate? prov:PMUpdateResponse? prov:PMDelete? prov:PMDeleteResponse? prov:Poll? prov:PollResponse? prov:UpdateEPR? prov:UpdateEPRResponse? idp:GetAssertion? idp:GetAssertionResponse? idp:GetProviderInfo? idp:GetProviderInfoResponse? idp:CreatedStatus? idp:CreatedStatusResponse? shps:Delete? shps:DeleteResponse? shps:GetStatus? shps:GetStatusResponse? shps:Query? shps:QueryResponse? shps:Invoke? shps:InvokeResponse? shps:QueryRegistered? shps:QueryRegisteredResponse? shps:Register? shps:RegisterResponse? shps:SetStatus? shps:SetStatusResponse? shps:Update? shps:UpdateResponse? shps:Poll? shps:PollResponse? shps:ProxyInvoke? shps:ProxyInvokeResponse? idhrxml:Create? idhrxml:CreateResponse? idhrxml:Query? idhrxml:QueryResponse? idhrxml:Modify? idhrxml:ModifyResponse? idhrxml:Delete? idhrxml:DeleteResponse? idhrxml:Notify? idhrxml:NotifyResponse? @id? -> %xs:ID ; @mustUnderstand -> %xs:boolean @actor -> %xs:anyURI @encodingStyle -> %xs:anyURI &@encodingStyle: @e:encodingStyle? ; Fault -> %e:Fault %Fault: e:faultcode -> %xs:QName e:faultstring -> %xs:string e:faultactor? -> %xs:anyURI e:detail? -> %e:detail ; %detail: any* @any ; #EOF
# xmldsig-core.sg -- Slightly edited after generation
# $Id: xmldsig-core.sg,v 1.3 2007-09-24 02:34:34 sampo Exp $
target(ds, http://www.w3.org/2000/09/xmldsig#)
ns(xs, http://www.w3.org/2001/XMLSchema)
ns(exca, http://www.w3.org/2001/10/xml-exc-c14n#)
ns(xenc, http://www.w3.org/2001/04/xmlenc#)
%CryptoBinary: base(xs:base64Binary) ;
Signature -> %ds:SignatureType
%SignatureType:
ds:SignedInfo
ds:SignatureValue
ds:KeyInfo?
ds:Object*
@Id? -> %xs:ID
;
SignatureValue -> %ds:SignatureValueType
%SignatureValueType: base(xs:base64Binary)
@Id? -> %xs:ID
;
SignedInfo -> %ds:SignedInfoType
%SignedInfoType:
ds:CanonicalizationMethod
ds:SignatureMethod
ds:Reference+
@Id? -> %xs:ID
;
CanonicalizationMethod -> %ds:CanonicalizationMethodType
%CanonicalizationMethodType:
any*
@Algorithm -> %xs:anyURI
;
SignatureMethod -> %ds:SignatureMethodType
%SignatureMethodType:
ds:HMACOutputLength? -> %ds:HMACOutputLengthType
any*
@Algorithm -> %xs:anyURI
;
Reference -> %ds:ReferenceType
%ReferenceType:
ds:Transforms?
ds:DigestMethod
ds:DigestValue
@Id? -> %xs:ID
@URI? -> %xs:anyURI
@Type? -> %xs:anyURI
;
Transforms -> %ds:TransformsType
%TransformsType:
ds:Transform+
;
Transform -> %ds:TransformType
%TransformType:
ds:XPath* -> %xs:string
exca:InclusiveNamespaces?
any*
@Algorithm -> %xs:anyURI
;
DigestMethod -> %ds:DigestMethodType
%DigestMethodType:
any*
@Algorithm -> %xs:anyURI
;
DigestValue -> %ds:DigestValueType
%DigestValueType: base(xs:base64Binary) ;
KeyInfo -> %ds:KeyInfoType
%KeyInfoType:
ds:KeyName*
ds:KeyValue*
ds:RetrievalMethod*
ds:X509Data*
ds:PGPData*
ds:SPKIData*
ds:MgmtData*
xenc:EncryptedKey*
any*
@Id? -> %xs:ID
;
KeyName -> %xs:string
MgmtData -> %xs:string
KeyValue -> %ds:KeyValueType
%KeyValueType:
ds:DSAKeyValue?
ds:RSAKeyValue?
any?
;
RetrievalMethod -> %ds:RetrievalMethodType
%RetrievalMethodType:
ds:Transforms?
@URI? -> %xs:anyURI
@Type? -> %xs:anyURI
;
X509Data -> %ds:X509DataType
%X509DataType:
ds:X509IssuerSerial* -> %ds:X509IssuerSerialType
ds:X509SKI* -> %xs:base64Binary
ds:X509SubjectName* -> %xs:string
ds:X509Certificate* -> %xs:base64Binary
ds:X509CRL* -> %xs:base64Binary
any*
;
%X509IssuerSerialType:
ds:X509IssuerName -> %xs:string
ds:X509SerialNumber -> %xs:integer
;
PGPData -> %ds:PGPDataType
%PGPDataType:
ds:PGPKeyID? -> %xs:base64Binary
ds:PGPKeyPacket? -> %xs:base64Binary
any*
;
SPKIData -> %ds:SPKIDataType
%SPKIDataType:
ds:SPKISexp -> %xs:base64Binary
any?
;
Object -> %ds:ObjectType
%ObjectType:
any* processContents(lax)
@Id? -> %xs:ID
@MimeType? -> %xs:string
@Encoding? -> %xs:anyURI
;
Manifest -> %ds:ManifestType
%ManifestType:
ds:Reference+
@Id? -> %xs:ID
;
SignatureProperties -> %ds:SignaturePropertiesType
%SignaturePropertiesType:
ds:SignatureProperty+
@Id? -> %xs:ID
;
SignatureProperty -> %ds:SignaturePropertyType
%SignaturePropertyType:
any+
@Target -> %xs:anyURI
@Id? -> %xs:ID
;
%HMACOutputLengthType: base(xs:integer) ;
DSAKeyValue -> %ds:DSAKeyValueType
%DSAKeyValueType:
ds:P? -> %ds:CryptoBinary
ds:Q? -> %ds:CryptoBinary
ds:G? -> %ds:CryptoBinary
ds:Y -> %ds:CryptoBinary
ds:J? -> %ds:CryptoBinary
ds:Seed? -> %ds:CryptoBinary
ds:PgenCounter? -> %ds:CryptoBinary
;
RSAKeyValue -> %ds:RSAKeyValueType
%RSAKeyValueType:
ds:Modulus -> %ds:CryptoBinary
ds:Exponent -> %ds:CryptoBinary
;
#EOF
# xenc-schema.sg -- Slightly edited after generation
# $Id: xenc-schema.sg,v 1.2 2007-09-24 02:34:34 sampo Exp $
target(xenc,http://www.w3.org/2001/04/xmlenc#)
ns(xs,http://www.w3.org/2001/XMLSchema)
import(ds,http://www.w3.org/2000/09/xmldsig#,http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd)
%EncryptedType:
xenc:EncryptionMethod? -> %xenc:EncryptionMethodType
ds:KeyInfo?
xenc:CipherData
xenc:EncryptionProperties?
@Id? -> %xs:ID
@Type? -> %xs:anyURI
@MimeType? -> %xs:string
@Encoding? -> %xs:anyURI
;
%EncryptionMethodType:
xenc:KeySize? -> %xenc:KeySizeType
xenc:OAEPparams? -> %xs:base64Binary
any*
@Algorithm -> %xs:anyURI
;
%KeySizeType: base(xs:integer) ;
CipherData -> %xenc:CipherDataType
%CipherDataType:
xenc:CipherValue? -> %xs:base64Binary
xenc:CipherReference?
;
CipherReference -> %xenc:CipherReferenceType
%CipherReferenceType:
xenc:Transforms? -> %xenc:TransformsType
@URI -> %xs:anyURI
;
%TransformsType:
ds:Transform+
;
EncryptedData -> %xenc:EncryptedDataType
%EncryptedDataType: base(xenc:EncryptedType) ;
EncryptedKey -> %xenc:EncryptedKeyType
%EncryptedKeyType: base(xenc:EncryptedType)
xenc:ReferenceList?
xenc:CarriedKeyName? -> %xs:string
@Recipient? -> %xs:string
;
AgreementMethod -> %xenc:AgreementMethodType
%AgreementMethodType:
xenc:KA-Nonce? -> %xs:base64Binary
any*
xenc:OriginatorKeyInfo? -> %ds:KeyInfoType
xenc:RecipientKeyInfo? -> %ds:KeyInfoType
@Algorithm -> %xs:anyURI
;
ReferenceList:
xenc:DataReference? -> %xenc:ReferenceType
xenc:KeyReference? -> %xenc:ReferenceType
;
%ReferenceType:
any*
@URI -> %xs:anyURI
;
EncryptionProperties -> %xenc:EncryptionPropertiesType
%EncryptionPropertiesType:
xenc:EncryptionProperty+
@Id? -> %xs:ID
;
EncryptionProperty -> %xenc:EncryptionPropertyType
%EncryptionPropertyType:
any*
@Target? -> %xs:anyURI
@Id? -> %xs:ID
@any?
;
#EOF
# zxid/sg/ws-addr-1.0.sg # Slightly edited, 5.9.2006, Sampo Kellomaki (sampo@iki.fi) # 6.2.2007, Added Discovery specifics to the Metadata --Sampo # $Id: ws-addr-1.0.sg,v 1.9 2007-09-30 05:10:03 sampo Exp $ target(a, http://www.w3.org/2005/08/addressing) #t arget(a, http://schemas.xmlsoap.org/ws/2004/08/addressing) # used by WS Federation? import(di, urn:liberty:disco:2006-08, liberty-idwsf-disco-svc-v2.0.xsd) import(e, http://schemas.xmlsoap.org/soap/envelope/) import(wsu, http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd,wss-util-1.0.xsd) ns(sbf, urn:liberty:sb) ns(b, urn:liberty:sb:2006-08) &@hdrs: @wsu:Id? @e:mustUnderstand? @e:actor? @id? -> %xs:anyURI @ID? -> %xs:anyURI ; EndpointReference -> %a:EndpointReferenceType %EndpointReferenceType: a:Address -> %a:AttributedURIType a:ReferenceParameters? a:Metadata? @notOnOrAfter? -> %xs:dateTime # Added by Sampo &@a:hdrs # Added by Sampo any* ns(##other) processContents(lax) @any ; ReferenceParameters -> %a:ReferenceParametersType %ReferenceParametersType: &@a:hdrs # Added by Sampo b:TargetIdentity* any* processContents(lax) @any ; Metadata -> %a:MetadataType %MetadataType: sbf:Framework? di:Abstract? di:ProviderID? di:ServiceType? di:SecurityContext? any* processContents(lax) @any ; MessageID -> %a:AttributedURIType RelatesTo -> %a:RelatesToType %RelatesToType: base(xs:anyURI) @RelationshipType? -> %a:RelationshipTypeOpenEnum # default (http://www.w3.org/2005/08/addressing/reply) &@a:hdrs # Added by Sampo @any ; %RelationshipTypeOpenEnum: union(a:RelationshipType xs:anyURI) ; %RelationshipType: enum( http://www.w3.org/2005/08/addressing/reply ) ; ReplyTo -> %a:EndpointReferenceType From -> %a:EndpointReferenceType FaultTo -> %a:EndpointReferenceType To -> %a:AttributedURIType Action -> %a:AttributedURIType %AttributedURIType: base(xs:anyURI) &@a:hdrs # Added by Sampo @any ; @IsReferenceParameter -> %xs:boolean %FaultCodesOpenEnumType: union(a:FaultCodesType xs:QName) ; %FaultCodesType: enum( a:InvalidAddressingHeader a:InvalidAddress a:InvalidEPR a:InvalidCardinality a:MissingAddressInEPR a:DuplicateMessageID a:ActionMismatch a:MessageAddressingHeaderRequired a:DestinationUnreachable a:ActionNotSupported a:EndpointUnavailable ) ; RetryAfter -> %a:AttributedUnsignedLongType %AttributedUnsignedLongType: base(xs:unsignedLong) &@a:hdrs # Added by Sampo @any ; ProblemHeaderQName -> %a:AttributedQNameType %AttributedQNameType: base(xs:QName) &@a:hdrs # Added by Sampo @any ; ProblemHeader -> %a:AttributedAnyType %AttributedAnyType: any* processContents(lax) &@a:hdrs # Added by Sampo @any ; ProblemURI -> %a:AttributedURIType ProblemAction -> %a:ProblemActionType %ProblemActionType: a:Action? a:SoapAction? -> %xs:anyURI &@a:hdrs # Added by Sampo @any ; #EOF
These XML blobs are for reference. They have been pretty printed. Indentation indicates nesting level and closing tags have been abbreviated as "</>". The actual XML on wire generally does not have any whitespace.
This example corresponds to t/sso-w-bootstraps.xml in the distribution.
Both bootstraps illustrate SAML assertion as bearer token.
<soap:Envelope
xmlns:lib="urn:liberty:iff:2003-08"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soap:Body>
<sp:ArtifactResponse
xmlns:sp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="REvgoIIlkzTmk-aIX6tKE"
InResponseTo="RfAsltVf2"
IssueInstant="2007-02-10T05:38:15Z"
Version="2.0">
<sa:Issuer
xmlns:sa="urn:oasis:names:tc:SAML:2.0:assertion"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
https://a-idp.liberty-iop.org:8881/idp.xml</>
<sp:Status>
<sp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></>
<sp:Response
xmlns:sp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="RCCzu13z77SiSXqsFp1u1"
InResponseTo="NojFIIhxw"
IssueInstant="2007-02-10T05:37:42Z"
Version="2.0">
<sa:Issuer
xmlns:sa="urn:oasis:names:tc:SAML:2.0:assertion"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
https://a-idp.liberty-iop.org:8881/idp.xml</>
<sp:Status>
<sp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></>
<sa:Assertion
xmlns:sa="urn:oasis:names:tc:SAML:2.0:assertion"
ID="ASSE6bgfaV-sapQsAilXOvBu"
IssueInstant="2007-02-10T05:37:42Z"
Version="2.0">
<sa:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
https://a-idp.liberty-iop.org:8881/idp.xml</>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#ASSE6bgfaV-sapQsAilXOvBu">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>r8OvtNmq5LkYwCNg6bsRZAdT4NE=</></></>
<ds:SignatureValue>GtWVZzHYW54ioHk/C7zjDRThohrpwC4=</></>
<sa:Subject>
<sa:NameID
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameQualifier="https://a-idp.liberty-iop.org:8881/idp.xml">PB5fLIA4lRU2bH4HkQsn9</>
<sa:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<sa:SubjectConfirmationData
NotOnOrAfter="2007-02-10T06:37:41Z"
Recipient="https://sp1.zxidsp.org:8443/zxidhlo?o=B"/></></>
<sa:Conditions
NotBefore="2007-02-10T05:32:42Z"
NotOnOrAfter="2007-02-10T06:37:42Z">
<sa:AudienceRestriction>
<sa:Audience>https://sp1.zxidsp.org:8443/zxidhlo?o=B</></></>
<sa:Advice>
<!-- This assertion is the credential for the ID-WSF 1.1 bootstrap (below). -->
<sa:Assertion
ID="CREDOTGAkvhNoP1aiTq4bXBg"
IssueInstant="2007-02-10T05:37:42Z"
Version="2.0">
<sa:Issuer
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
https://a-idp.liberty-iop.org:8881/idp.xml</>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#CREDOTGAkvhNoP1aiTq4bXBg">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>dqq/28hw5eEv+ceFyiLImeJ1P8w=</></></>
<ds:SignatureValue>UKlEgHKQwuoCE=</></>
<sa:Subject>
<sa:NameID/> <!-- *** Bug here!!! -->
<sa:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/></>
<sa:Conditions
NotBefore="2007-02-10T05:32:42Z"
NotOnOrAfter="2007-02-10T06:37:42Z">
<sa:AudienceRestriction>
<sa:Audience>https://sp1.zxidsp.org:8443/zxidhlo?o=B</></></></></>
<sa:AuthnStatement
AuthnInstant="2007-02-10T05:37:42Z"
SessionIndex="1171085858-4">
<sa:AuthnContext>
<sa:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:Password</></></>
<sa:AttributeStatement>
<!-- Regular attribute -->
<sa:Attribute
Name="cn"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<sa:AttributeValue>Sue</></>
<!-- ID-WSF 1.1 Bootstrap for discovery. See also the Advice, above. -->
<sa:Attribute
Name="DiscoveryResourceOffering"
NameFormat="urn:liberty:disco:2003-08">
<sa:AttributeValue>
<di12:ResourceOffering
xmlns:di12="urn:liberty:disco:2003-08"
entryID="2">
<di12:ResourceID>
https://a-idp.liberty-iop.org/profiles/WSF1.1/RID-DISCO-sue</>
<di12:ServiceInstance>
<di12:ServiceType>urn:liberty:disco:2003-08</>
<di12:ProviderID>https://a-idp.liberty-iop.org:8881/idp.xml</>
<di12:Description>
<di12:SecurityMechID>urn:liberty:security:2005-02:TLS:Bearer</>
<di12:CredentialRef>CREDOTGAkvhNoP1aiTq4bXBg</>
<di12:Endpoint>https://a-idp.liberty-iop.org:8881/DISCO-S</></></>
<di12:Abstract>Symlabs Discovery Service Team G</></></></>
<!-- ID-WSF 2.0 Bootstrap for Discovery. The credential (bearer token) is inline. -->
<sa:Attribute
Name="urn:liberty:disco:2006-08:DiscoveryEPR"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<sa:AttributeValue>
<wsa:EndpointReference
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
notOnOrAfter="2007-02-10T07:37:42Z"
wsu:Id="EPRIDcjP8ObO9In47SDjO9b37">
<wsa:Address>https://a-idp.liberty-iop.org:8881/DISCO-S</>
<wsa:Metadata xmlns:di="urn:liberty:disco:2006-08">
<di:Abstract>SYMfiam Discovery Service</>
<sbf:Framework xmlns:sbf="urn:liberty:sb" version="2.0"/>
<di:ProviderID>https://a-idp.liberty-iop.org:8881/idp.xml</>
<di:ServiceType>urn:liberty:disco:2006-08</>
<di:SecurityContext>
<di:SecurityMechID>urn:liberty:security:2005-02:TLS:Bearer</>
<sec:Token
xmlns:sec="urn:liberty:security:2006-08"
usage="urn:liberty:security:tokenusage:2006-08:SecurityToken">
<sa:Assertion
ID="CREDV6ZBMyicmyvDq9pLIoSR"
IssueInstant="2007-02-10T05:37:42Z"
Version="2.0">
<sa:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
https://a-idp.liberty-iop.org:8881/idp.xml</>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#CREDV6ZBMyicmyvDq9pLIoSR">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>o2SgbuKIBzl4e0dQoTwiyqXr/8Y=</></></>
<ds:SignatureValue>hHdUKaZ//cZ8UYJxvTReNU=</></>
<sa:Subject>
<sa:NameID
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameQualifier="https://a-idp.liberty-iop.org:8881/idp.xml">
9my93VkP3tSxEOIb3ckvjLpn0pa6aV3yFXioWX-TzZI=</>
<sa:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/></>
<sa:Conditions
NotBefore="2007-02-10T05:32:42Z"
NotOnOrAfter="2007-02-10T06:37:42Z">
<sa:AudienceRestriction>
<sa:Audience>https://a-idp.liberty-iop.org:8881/idp.xml</></></>
<sa:AuthnStatement AuthnInstant="2007-02-10T05:37:42Z">
<sa:AuthnContext>
<sa:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:Password</></></></></></></></></></></></></></></></>
N.B. The AttributeStatement/Attribute/AttributeValue/ EndpointReference/Metadata/SecurityContext/ Token/Assertion/Conditions/AudienceRestriction/Audience is the same as the IdP because in many products the IdP and Discovery Service roles are implemented by the same entity. Note also that the audience of the inner assertion is the discovery service where as the audience of the outer assertion is the SP that will eventually call the Discovery Service.
<e:Envelope
xmlns:e="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:b="urn:liberty:sb:2005-11"
xmlns:sec="urn:liberty:security:2005-11"
xmlns:wsse="http://docs.oasis-open.org/wss/20 04/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsa="http://www.w3.org/2005/08/ addressing">
<e:Header>
<wsa:MessageID wsu:Id="MID">123</>
<wsa:To wsu:Id="TO">...</>
<wsa:Action wsu:Id="ACT">urn:xx:Query</>
<wsse:Security mustUnderstand="1">
<wsu:Timestamp wsu:Id="TS"><wsu:Created>2005-06-17T04:49:17Z</></>
<wsse:BinarySecurityToken
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"
wsu:Id="X509Token"
EncodingType="http://docs.oas is-open.org/wss/2004/01/oasis-200401-wss-soap-message-securiy-1.0#Base64Binary">
MIIB9zCCAWSgAwIBAgIQ...</>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:Reference URI="#MID">...</>
<ds:Reference URI="#TO">...</>
<ds:Reference URI="#ACT">...</>
<ds:Reference URI="#TS">...</>
<ds:Reference URI="#X509">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>Ru4cAfeBAB</></>
<ds:Reference URI="#BDY">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>YgGfS0pi56p</></></>
<ds:KeyInfo><wsse:SecurityTokenReference><wsse:Reference URI="#X509"/></></>
<ds:SignatureValue>HJJWbvqW9E84vJVQkjDElgscSXZ5Ekw==</></></></>
<e:Body wsu:Id="BDY">
<xx:Query/></></>
The salient features of the above XML blob are
Signature that covers relevant SOAP headers and Body
Absence of any explicit identity token.
Absence of identity token means that from the headers it is not possible to identify the taget identity. The signature generally coveys the Invoker identity (the WSC that is calling the service). Since one WSC typically serves many principals, knowing which principal is impossible. For this reason X509 security mechanism is seldom used in ID-WSF 2.0 world (with ID-WSF 1.1 the ResourceID provides an alternative way of identifying the principal, thus making X509 a viable option).
<e:Envelope
xmlns:e="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:b="urn:liberty:sb:2005-11"
xmlns:sec="urn:liberty:security:2005-11"
xmlns:wsse="http://docs.oasis-open.org/wss/20 04/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsa="http://www.w3.org/2005/03/ addressing">
<e:Header>
<wsa:MessageID wsu:Id="MID">...</>
<wsa:To wsu:Id="TO">...</>
<wsa:Action wsu:Id="ACT">urn:xx:Query</>
<wsse:Security mustUnderstand="1">
<wsu:Timestamp wsu:Id="TS">
<wsu:Created>2005-06-17T04:49:17Z</></>
<wsse:BinarySecurityToken
ValueType="anyNSPrefix:ServiceSess ionContext"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64 Binary"
wsu:Id="BST">
mQEMAzRniWkAAAEH9RWir0eKDkyFAB7PoFazx3ftp0vWwbbzqXdgcX8fpEqSr1v4
YqUc7OMiJcBtKBp3+jlD4HPUaurIqHA0vrdmMpM+sF2BnpND118f/mXCv3XbWhiL
VT4r9ytfpXBluelOV93X8RUz4ecZcDm9e+IEG+pQjnvgrSgac1NrW5K/CJEOUUjh
oGTrym0Ziutezhrw/gOeLVtkywsMgDr77gWZxRvw01w1ogtUdTceuRBIDANj+KVZ
vLKlTCaGAUNIjkiDDgti=</>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig #">
<ds:SignedInfo>
<ds:Reference URI="#MID">...</>
<ds:Reference URI="#TO">...</>
<ds:Reference URI="#ACT">...</>
<ds:Reference URI="#TS">...</>
<ds:Reference URI="#BST">...</>
<ds:Reference URI="#BDY">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1 "/>
<ds:DigestValue>YgGfS0pi56pu</></></>
...</></></>
<e:Body wsu:Id="BDY">
<xx:Query/></></>
<e:Envelope
xmlns:e="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sb="urn:liberty:sb:2005-11"
xmlns:sec="urn:liberty:security:2005-11"
xmlns:wsse="http://docs.oasis-open.org/wss/20 04/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<e:Header>
<sbf:Framework version="2.0-simple" e:mustUnderstand="1"
e:actor="http://schemas.../next"
wsu:Id="SBF"/>
<wsa:MessageID wsu:Id="MID">...</>
<wsa:To wsu:Id="TO">...</>
<wsa:Action wsu:Id="ACT">urn:xx:Query</>
<wsse:Security mustUnderstand="1">
<wsu:Timestamp wsu:Id="TS">
<wsu:Created>2005-06-17T04:49:17Z</></>
<sa:Assertion
xmlns:sa="urn:oasis:names:tc:SAML:2.0:assertion"
Version="2.0"
ID="A7N123"
IssueInstant="2005-04-01T16:58:33.173Z">
<sa:Issuer>http://idp.symdemo.com/idp.xml</>
<ds:Signature>...</>
<sa:Subject>
<sa:EncryptedID>
<xenc:EncryptedData>U2XTCNvRX7Bl1NK182nmY00TEk==</>
<xenc:EncryptedKey>...</></>
<sa:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/></>
<sa:Conditions
NotBefore="2005-04-01T16:57:20Z"
NotOnOrAfter="2005-04-01T21:42:4 3Z">
<sa:AudienceRestrictionCondition>
<sa:Audience>http://wsp.zxidsp.org</></></>
<sa:AuthnStatement
AuthnInstant="2005-04-01T16:57:30.000Z"
SessionIndex="6345789">
<sa:AuthnContext>
<sa:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</></></>
<sa:AttributeStatement>
<sa:EncryptedAttribute>
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element">
mQEMAzRniWkAAAEH9RbzqXdgcX8fpEqSr1v4=</>
<xenc:EncryptedKey>...</></></></>
<wsse:SecurityTokenReference
xmlns:wsse11="..."
wsu:Id="STR1"
wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<wsse:KeyIdentifier
ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">
A7N123</></>
<ds:Signature>
<ds:SignedInfo>
<ds:Reference URI="#MID">...</>
<ds:Reference URI="#TO">...</>
<ds:Reference URI="#ACT">...</>
<ds:Reference URI="#TS">...</>
<ds:Reference URI="#STR1">
<ds:Transform Algorithm="...#STR-Transform">
<wsse:TransformationParameters>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></></></>
<ds:Reference URI="#BDY"/></>
...</></></>
<e:Body wsu:Id="BDY">
<xx:Query/></></>
*** is the reference above to wsse11:TokenType really correct?
Note how the