Synch'd metadata transformation files from /c.
[java-idp.git] / src / schemas / metadata_v13_to_v12.xsl
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!--
3
4         v13_to_v12_sites.xsl
5         
6         XSL stylesheet converting a SAML 2 metadata file describing a Shibboleth
7         1.3 federation into the equivalent Shibboleth 1.2 sites file.
8         
9         Author: Ian A. Young <ian@iay.org.uk>
10
11         $Id$
12 -->
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">
21
22         <!--
23                 Version information for this file.  Remember to peel off the dollar signs
24                 before dropping the text into another versioned file.
25         -->
26         <xsl:param name="cvsId">$Id$</xsl:param>
27
28         <!--
29                 Add a comment to the start of the output file.
30         -->
31         <xsl:template match="/">
32                 <xsl:comment>
33                         <xsl:text>&#10;&#9;***DO NOT EDIT THIS FILE***&#10;&#10;</xsl:text>
34                         <xsl:text>&#9;Converted by:&#10;&#10;&#9;</xsl:text>
35                         <xsl:value-of select="substring-before(substring-after($cvsId, ': '), '$')"/>
36                         <xsl:text>&#10;</xsl:text>
37                 </xsl:comment>
38                 <xsl:apply-templates/>
39         </xsl:template>
40
41         <!--Force UTF-8 encoding for the output.-->
42         <xsl:output omit-xml-declaration="no" method="xml" encoding="UTF-8" indent="yes"/>
43
44         <!--
45                 Selectively strip empty text nodes from the input.
46         -->
47         <xsl:strip-space elements="md:EntityDescriptor"/>
48         
49         <!--
50                 Map EntitiesDescriptor to SiteGroup
51         -->
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>
56                         </xsl:attribute>
57                         <!--
58                                 Pass through text blocks and comments, and interesting elements.
59                                 These may be: EntityDescriptor or nested EntitiesDescriptor.
60                         -->
61                         <xsl:apply-templates select="text()|comment()|md:EntityDescriptor|md:EntitiesDescriptor"/>
62                 </SiteGroup>
63         </xsl:template>
64
65         <!--
66                 Map EntityDescriptor to whichever of OriginSite and/or DestinationSite apply.
67         -->
68         <xsl:template match="md:EntityDescriptor">
69                 <xsl:if test="md:IDPSSODescriptor">
70                         <xsl:call-template name="OriginSite"/>
71                 </xsl:if>
72                 <xsl:if test="md:SPSSODescriptor">
73                         <xsl:call-template name="DestinationSite"/>
74                 </xsl:if>
75         </xsl:template>
76
77         <!--
78                 Map appropriate EntityDescriptor to OriginSite
79         -->
80         <xsl:template name="OriginSite">
81                 <OriginSite Name="{@entityID}">
82                         <!-- ErrorURL attribute -->
83                         <xsl:apply-templates select="md:IDPSSODescriptor/@errorURL"/>
84
85                         <!--
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".
89                         -->
90                         <xsl:apply-templates select="descendant::comment()"/>
91
92                         <!--    Alias elements -->
93                         <xsl:apply-templates select="md:Organization"/>
94
95                         <!-- Contact elements -->
96                         <xsl:apply-templates select="md:ContactPerson"/>
97
98                         <!-- HandleService elements -->
99                         <xsl:apply-templates select="md:IDPSSODescriptor"/>
100
101                         <!-- AttributeAuthority elements -->
102                         <xsl:apply-templates select="md:AttributeAuthorityDescriptor/md:AttributeService"/>
103
104                         <!--
105                                 Domain elements
106                                 
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.
110                         -->
111                         <xsl:apply-templates select="md:AttributeAuthorityDescriptor/md:Extensions/shibmeta:Scope"/>
112
113                 </OriginSite>
114         </xsl:template>
115
116         <!--
117                 Map IDPSSODescriptor to HandleService
118         -->
119         <xsl:template match="md:IDPSSODescriptor">
120                 <HandleService Name="{md:KeyDescriptor/ds:KeyInfo/ds:KeyName}"
121                         Location="{md:SingleSignOnService/@Location}" 
122                 />
123         </xsl:template>
124
125         <!--
126                 Map AttributeService to AttributeAuthority
127         -->
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">
133                                 <xsl:choose>
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, ':')"/>
137                                         </xsl:when>
138                                         <!-- otherwise if the port is absent we just use the host unchanged -->
139                                         <xsl:otherwise>
140                                                 <xsl:value-of select="$host"/>
141                                         </xsl:otherwise>
142                                 </xsl:choose>
143                         </xsl:attribute>
144                 </AttributeAuthority>
145         </xsl:template>
146
147         <!--
148                 Map Scope to Domain
149         -->
150         <xsl:template match="shibmeta:Scope">
151                 <Domain>
152                         <xsl:apply-templates select="@regexp"/>
153                         <xsl:value-of select="."/>
154                 </Domain>
155         </xsl:template>
156
157         <!--
158                 Map appropriate EntityDescriptor to DestinationSite
159         -->
160         <xsl:template name="DestinationSite">
161                 <DestinationSite Name="{@entityID}">
162                         <!-- ErrorURL attribute -->
163                         <xsl:apply-templates select="md:SPSSODescriptor/@errorURL"/>
164
165                         <!--
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".
169                         -->
170                         <xsl:apply-templates select="descendant::comment()"/>
171
172                         <!--    Alias elements -->
173                         <xsl:apply-templates select="md:Organization"/>
174
175                         <!-- Contact elements -->
176                         <xsl:apply-templates select="md:ContactPerson"/>
177
178                         <!-- AssertionConsumerServiceURL elements -->
179                         <xsl:apply-templates
180                                 select="md:SPSSODescriptor/md:AssertionConsumerService[@Binding='urn:oasis:names:tc:SAML:1.0:profiles:browser-post']"/>
181
182                         <!-- AttributeRequester elements -->
183                         <xsl:apply-templates select="md:SPSSODescriptor/md:KeyDescriptor/ds:KeyInfo/ds:KeyName"/>
184                 </DestinationSite>
185         </xsl:template>
186
187         <!--
188                 Map AssertionConsumerService to AssertionConsumerServiceURL
189         -->
190         <xsl:template match="md:AssertionConsumerService">
191                 <AssertionConsumerServiceURL Location="{@Location}"/>
192         </xsl:template>
193
194         <!--
195                 Map ds:KeyName to AttributeRequester
196         -->
197         <xsl:template match="ds:KeyName">
198                 <AttributeRequester Name="{.}"/>
199         </xsl:template>
200         
201         <!--
202                 Map Organization to a sequence of Alias elements.
203
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.
207         -->
208         <xsl:template match="md:Organization">
209                 <xsl:param name="nName" select="count(md:OrganizationName)"/>
210                 <xsl:param name="nDisp" select="count(md:OrganizationDisplayName)"/>
211                 <xsl:choose>
212                         <xsl:when test="$nName=1 and $nDisp=1 and md:OrganizationName = md:OrganizationDisplayName">
213                                 <xsl:apply-templates select="md:OrganizationDisplayName"/>
214                         </xsl:when>
215                         <xsl:otherwise>
216                                 <xsl:apply-templates select="md:OrganizationName"/>
217                                 <xsl:apply-templates select="md:OrganizationDisplayName"/>
218                         </xsl:otherwise>
219                 </xsl:choose>
220         </xsl:template>
221
222         <!--
223                 Map OrganizationName or OrganizationDisplayName to Alias
224         -->
225         <xsl:template match="md:OrganizationName|md:OrganizationDisplayName">
226                 <Alias>
227                         <xsl:if test="@xml:lang != 'en'">
228                                 <xsl:apply-templates select="@xml:lang"/>
229                         </xsl:if>
230                         <xsl:value-of select="."/>
231                 </Alias>
232         </xsl:template>
233
234         <!--
235                 Map Contact to ContactPerson
236                 
237                 Cope with:
238                         * absence of optional EmailAddress
239                         * malformed EmailAddress (no mailto:)
240                         * mixtures of GivenName and SurName
241         -->
242         <xsl:template match="md:ContactPerson">
243                 <Contact Type="{@contactType}">
244                         <!-- Email attribute -->
245                         <xsl:choose>
246                                 <xsl:when test="starts-with(md:EmailAddress, 'mailto:')">
247                                         <xsl:attribute name="Email">
248                                                 <xsl:value-of select="substring-after(md:EmailAddress, 'mailto:')"/>
249                                         </xsl:attribute>
250                                 </xsl:when>
251                                 <xsl:when test="md:EmailAddress">
252                                         <xsl:attribute name="Email">
253                                                 <xsl:value-of select="md:EmailAddress"/>
254                                         </xsl:attribute>
255                                 </xsl:when>
256                                 <xsl:otherwise>
257                                         <!-- omit Email attribute if in doubt -->
258                                 </xsl:otherwise>
259                         </xsl:choose>
260                         <!-- Name attribute -->
261                         <xsl:choose>
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>
264                                 </xsl:when>
265                                 <xsl:when test="md:GivenName">
266                                         <xsl:attribute name="Name"><xsl:value-of select="md:GivenName"/></xsl:attribute>
267                                 </xsl:when>
268                                 <xsl:otherwise>
269                                         <xsl:attribute name="Name">Nobody</xsl:attribute>
270                                 </xsl:otherwise>
271                         </xsl:choose>
272                 </Contact>
273         </xsl:template>
274         
275         <!--
276                 Map @errorURL to @ErrorURL
277         -->
278         <xsl:template match="@errorURL">
279                 <xsl:attribute name="ErrorURL"><xsl:value-of select="."/></xsl:attribute>
280         </xsl:template>
281
282         <!--
283                 By default, copy referenced attributes through unchanged.
284         -->
285         <xsl:template match="@*">
286                 <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
287         </xsl:template>
288
289         <!--
290                 By default, copy comments through to the output unchanged, but strip extra text.
291         -->
292         <xsl:template match="comment()">
293                 <xsl:copy/>
294         </xsl:template>
295         <xsl:template match="text()"/>
296
297 </xsl:stylesheet>
298