3 # Copyright (C) 2014 Simo Sorce <simo@redhat.com>
5 # see file 'COPYING' for use and warranty information
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from ipsilon.providers.saml2.certs import Certificate
21 from lxml import etree
25 EDESC = '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF
27 'md': lasso.SAML2_METADATA_HREF,
31 IDPDESC = 'IDPSSODescriptor'
32 SPDESC = 'SPSSODescriptor'
37 SSO_SERVICE = 'SingleSignOnService'
38 LOGOUT_SERVICE = 'SingleLogoutService'
39 ASSERTION_SERVICE = 'AssertionConsumerService'
42 def mdElement(_parent, _tag, **kwargs):
43 tag = '{%s}%s' % (lasso.SAML2_METADATA_HREF, _tag)
44 return etree.SubElement(_parent, tag, **kwargs)
47 def dsElement(_parent, _tag, **kwargs):
48 tag = '{%s}%s' % (lasso.DS_HREF, _tag)
49 return etree.SubElement(_parent, tag, **kwargs)
52 class Metadata(object):
54 def __init__(self, role=None):
55 self.root = etree.Element(EDESC, nsmap=NSMAP)
60 def set_entity_id(self, url):
62 self.root.set('entityID', url)
64 def set_role(self, role):
67 elif role == IDP_ROLE:
72 raise ValueError('invalid role: %s' % role)
73 self.role = mdElement(self.root, description)
74 self.role.set('protocolSupportEnumeration', lasso.SAML2_PROTOCOL_HREF)
77 def add_cert(self, certdata, use):
78 desc = mdElement(self.role, 'KeyDescriptor')
80 info = dsElement(desc, 'KeyInfo')
81 data = dsElement(info, 'X509Data')
82 cert = dsElement(data, 'X509Certificate')
85 def add_certs(self, signcert=None, enccert=None):
87 self.add_cert(signcert.get_cert(), 'signing')
89 self.add_cert(enccert.get_cert(), 'encryption')
91 def add_service(self, svctype, binding, location):
92 svc = mdElement(self.role, svctype)
93 svc.set('Binding', binding)
94 svc.set('Location', location)
96 def add_allowed_name_format(self, name_format):
97 nameidfmt = mdElement(self.role, 'NameIDFormat')
98 nameidfmt.text = name_format
100 def output(self, path):
101 data = etree.tostring(self.root, xml_declaration=True,
102 encoding='UTF-8', pretty_print=True)
103 with open(path, 'w') as f:
107 if __name__ == '__main__':
108 from ipsilon.providers.saml2.provider import NAMEID_MAP
113 tmpdir = tempfile.mkdtemp()
116 # Test IDP generation
117 sign_cert = Certificate(tmpdir)
118 sign_cert.generate('idp-signing-cert', 'idp.ipsilon.example.com')
119 enc_cert = Certificate(tmpdir)
120 enc_cert.generate('idp-encryption-cert', 'idp.ipsilon.example.com')
122 idp.set_entity_id('https://ipsilon.example.com/idp/metadata')
123 idp.set_role(IDP_ROLE)
124 idp.add_certs(sign_cert, enc_cert)
125 idp.add_service(SSO_SERVICE, lasso.SAML2_METADATA_BINDING_POST,
126 'https://ipsilon.example.com/idp/saml2/POST')
127 idp.add_service(SSO_SERVICE, lasso.SAML2_METADATA_BINDING_REDIRECT,
128 'https://ipsilon.example.com/idp/saml2/Redirect')
130 idp.add_allowed_name_format(NAMEID_MAP[k])
131 md_file = os.path.join(tmpdir, 'metadata.xml')
133 with open(md_file) as fd:
135 print '==================== IDP ===================='
137 print '============================================='
140 sign_cert = Certificate(tmpdir)
141 sign_cert.generate('sp-signing-cert', 'sp.ipsilon.example.com')
143 sp.set_entity_id('https://ipsilon.example.com/samlsp/metadata')
145 sp.add_certs(sign_cert)
146 sp.add_service(LOGOUT_SERVICE, lasso.SAML2_METADATA_BINDING_REDIRECT,
147 'https://ipsilon.example.com/samlsp/logout')
148 sp.add_service(ASSERTION_SERVICE, lasso.SAML2_METADATA_BINDING_POST,
149 'https://ipsilon.example.com/samlsp/postResponse')
150 md_file = os.path.join(tmpdir, 'metadata.xml')
152 with open(md_file) as fd:
154 print '===================== SP ===================='
156 print '============================================='
159 shutil.rmtree(tmpdir)