1 <?xml version="1.0" encoding="UTF-8"?>
6 XSL stylesheet converting a SAML 2 metadata file describing a Shibboleth
7 1.3 federation into the equivalent Shibboleth 1.2 sites file.
9 Author: Ian A. Young <ian@iay.org.uk>
13 <xsl:stylesheet version="1.0"
14 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
15 xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
16 xmlns:shibmeta="urn:mace:shibboleth:metadata:1.0"
17 xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
18 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 xmlns="urn:mace:shibboleth:1.0"
20 exclude-result-prefixes="shibmeta md ds">
23 Version information for this file. Remember to peel off the dollar signs
24 before dropping the text into another versioned file.
26 <xsl:param name="cvsId">$Id$</xsl:param>
29 Add a comment to the start of the output file.
31 <xsl:template match="/">
33 <xsl:text> 	***DO NOT EDIT THIS FILE*** </xsl:text>
34 <xsl:text>	Converted by: 	</xsl:text>
35 <xsl:value-of select="substring-before(substring-after($cvsId, ': '), '$')"/>
36 <xsl:text> </xsl:text>
38 <xsl:apply-templates/>
41 <!--Force UTF-8 encoding for the output.-->
42 <xsl:output omit-xml-declaration="no" method="xml" encoding="UTF-8" indent="yes"/>
45 Selectively strip empty text nodes from the input.
47 <xsl:strip-space elements="md:EntityDescriptor"/>
50 Map EntitiesDescriptor to SiteGroup
52 <xsl:template match="md:EntitiesDescriptor">
53 <SiteGroup Name="{@Name}">
54 <xsl:attribute name="xsi:schemaLocation">
55 <xsl:text>urn:mace:shibboleth:1.0 shibboleth.xsd</xsl:text>
58 Pass through text blocks and comments, and interesting elements.
59 These may be: EntityDescriptor or nested EntitiesDescriptor.
61 <xsl:apply-templates select="text()|comment()|md:EntityDescriptor|md:EntitiesDescriptor"/>
66 Map EntityDescriptor to whichever of OriginSite and/or DestinationSite apply.
68 <xsl:template match="md:EntityDescriptor">
69 <xsl:if test="md:IDPSSODescriptor">
70 <xsl:call-template name="OriginSite"/>
72 <xsl:if test="md:SPSSODescriptor">
73 <xsl:call-template name="DestinationSite"/>
78 Map appropriate EntityDescriptor to OriginSite
80 <xsl:template name="OriginSite">
81 <OriginSite Name="{@entityID}">
82 <!-- ErrorURL attribute -->
83 <xsl:apply-templates select="md:IDPSSODescriptor/@errorURL"/>
86 Copy through all comments at the start of the output element.
87 This means we don't lose comments, but there is no way to guarantee they will
88 come out "in the right place".
90 <xsl:apply-templates select="descendant::comment()"/>
92 <!-- Alias elements -->
93 <xsl:apply-templates select="md:Organization"/>
95 <!-- Contact elements -->
96 <xsl:apply-templates select="md:ContactPerson"/>
98 <!-- HandleService elements -->
99 <xsl:apply-templates select="md:IDPSSODescriptor"/>
101 <!-- AttributeAuthority elements -->
102 <xsl:apply-templates select="md:AttributeAuthorityDescriptor/md:AttributeService"/>
107 These may come from Scope elements under either of two md elements. We pass
108 through only the ones from the AttributeAuthorityDescriptor as we know that 1.2
109 sites don't have scopes associated with the SSO.
111 <xsl:apply-templates select="md:AttributeAuthorityDescriptor/md:Extensions/shibmeta:Scope"/>
117 Map IDPSSODescriptor to HandleService
119 <xsl:template match="md:IDPSSODescriptor">
120 <HandleService Name="{md:KeyDescriptor/ds:KeyInfo/ds:KeyName}"
121 Location="{md:SingleSignOnService/@Location}"
126 Map AttributeService to AttributeAuthority
128 <xsl:template match="md:AttributeService">
129 <!-- pull out the host component of the location, after the // and before the next / -->
130 <xsl:param name="host" select="substring-before(substring-after(@Location, '//'), '/')"/>
131 <AttributeAuthority Location="{@Location}">
132 <xsl:attribute name="Name">
134 <!-- take off a trailing :port from the host, if present -->
135 <xsl:when test="substring-before($host, ':') != ''">
136 <xsl:value-of select="substring-before($host, ':')"/>
138 <!-- otherwise if the port is absent we just use the host unchanged -->
140 <xsl:value-of select="$host"/>
144 </AttributeAuthority>
150 <xsl:template match="shibmeta:Scope">
152 <xsl:apply-templates select="@regexp"/>
153 <xsl:value-of select="."/>
158 Map appropriate EntityDescriptor to DestinationSite
160 <xsl:template name="DestinationSite">
161 <DestinationSite Name="{@entityID}">
162 <!-- ErrorURL attribute -->
163 <xsl:apply-templates select="md:SPSSODescriptor/@errorURL"/>
166 Copy through all comments at the start of the output element.
167 This means we don't lose comments, but there is no way to guarantee they will
168 come out "in the right place".
170 <xsl:apply-templates select="descendant::comment()"/>
172 <!-- Alias elements -->
173 <xsl:apply-templates select="md:Organization"/>
175 <!-- Contact elements -->
176 <xsl:apply-templates select="md:ContactPerson"/>
178 <!-- AssertionConsumerServiceURL elements -->
180 select="md:SPSSODescriptor/md:AssertionConsumerService[@Binding='urn:oasis:names:tc:SAML:1.0:profiles:browser-post']"/>
182 <!-- AttributeRequester elements -->
183 <xsl:apply-templates select="md:SPSSODescriptor/md:KeyDescriptor/ds:KeyInfo/ds:KeyName"/>
188 Map AssertionConsumerService to AssertionConsumerServiceURL
190 <xsl:template match="md:AssertionConsumerService">
191 <AssertionConsumerServiceURL Location="{@Location}"/>
195 Map ds:KeyName to AttributeRequester
197 <xsl:template match="ds:KeyName">
198 <AttributeRequester Name="{.}"/>
202 Map Organization to a sequence of Alias elements.
204 The common case is that there are exactly one of each of OrganizationName and
205 OrganizationDisplayName, and that they are equal. In that case, just convert the
206 OrganizationDisplayName into an Alias. Otherwise, convert them all.
208 <xsl:template match="md:Organization">
209 <xsl:param name="nName" select="count(md:OrganizationName)"/>
210 <xsl:param name="nDisp" select="count(md:OrganizationDisplayName)"/>
212 <xsl:when test="$nName=1 and $nDisp=1 and md:OrganizationName = md:OrganizationDisplayName">
213 <xsl:apply-templates select="md:OrganizationDisplayName"/>
216 <xsl:apply-templates select="md:OrganizationName"/>
217 <xsl:apply-templates select="md:OrganizationDisplayName"/>
223 Map OrganizationName or OrganizationDisplayName to Alias
225 <xsl:template match="md:OrganizationName|md:OrganizationDisplayName">
227 <xsl:if test="@xml:lang != 'en'">
228 <xsl:apply-templates select="@xml:lang"/>
230 <xsl:value-of select="."/>
235 Map Contact to ContactPerson
238 * absence of optional EmailAddress
239 * malformed EmailAddress (no mailto:)
240 * mixtures of GivenName and SurName
242 <xsl:template match="md:ContactPerson">
243 <Contact Type="{@contactType}">
244 <!-- Email attribute -->
246 <xsl:when test="starts-with(md:EmailAddress, 'mailto:')">
247 <xsl:attribute name="Email">
248 <xsl:value-of select="substring-after(md:EmailAddress, 'mailto:')"/>
251 <xsl:when test="md:EmailAddress">
252 <xsl:attribute name="Email">
253 <xsl:value-of select="md:EmailAddress"/>
257 <!-- omit Email attribute if in doubt -->
260 <!-- Name attribute -->
262 <xsl:when test="md:GivenName and md:SurName">
263 <xsl:attribute name="Name"><xsl:value-of select="concat(md:GivenName, ' ', md:SurName)"/></xsl:attribute>
265 <xsl:when test="md:GivenName">
266 <xsl:attribute name="Name"><xsl:value-of select="md:GivenName"/></xsl:attribute>
268 <xsl:when test="md:SurName">
269 <xsl:attribute name="Name"><xsl:value-of select="md:SurName"/></xsl:attribute>
272 <xsl:attribute name="Name">Nobody</xsl:attribute>
279 Map @errorURL to @ErrorURL
281 <xsl:template match="@errorURL">
282 <xsl:attribute name="ErrorURL"><xsl:value-of select="."/></xsl:attribute>
286 By default, copy referenced attributes through unchanged.
288 <xsl:template match="@*">
289 <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
293 By default, copy comments through to the output unchanged, but strip extra text.
295 <xsl:template match="comment()">
298 <xsl:template match="text()"/>