SmeeGen
SmeeGen is an extension to Smee that generates new SAML metadata. It's mainly intended to create
SAML-format metadata for the non-SAML authentication protocols, CAS and OIDC, that are supported by the
Shibboleth IdP, but will also be able to create vanilla SAML metadata too. At present only SAML SPs, CAS
clients and OIDC RPs are supported.
Unlike other Smee extensions SmeeGen does not depend on the Smee package and can be installed on its own.
Features
- Create new CAS client records in SAML metadata format
- Create new OpenID Connect and Oauth RP records in SAML metadata format
- Create new metadata records for SAML SPs (work in progress)
- And that's it - this is profoundly uninteresting software unless you need to automate the creation of metadata
Uses
- Converting OIDC and CAS configurations into SAML format allows the use of many more Shibboleth IdP features:
- Friendly MDUI names, logos and privacy information
- Registration information
- Organization data
- Metadata-driven configuration
- Contacts - these are incredibly helpful when managing lots of metadata in a large organization
- Moving CAS and OIDC services over to an existing Shibboleth IdP can reduce the number of services needed, and reduce costs and risks. SmeeGen can be used to automate the migration of services by converting their configuration into SAML metadata
- SmeeGen can be combined with a UI to manage metadata for local services.
SmeeGen is not intended to be used for federated services - it's focused on metadata for services within an organization.
Progress
- OIDC RP metadata
- CAS client metadata
- SAML SP metadata (WIP)
- Templates for common software and apps
- Comprehensive tests
Examples
Create a very minimal CAS metadata entry
SmeeGen.cas!("https://sp.example.org")
outputs:
<EntityDescriptor entityID="https://sp.example.org" xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"
xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi">
<SPSSODescriptor protocolSupportEnumeration="https://www.apereo.org/cas/protocol">
<SingleLogoutService Binding="https://www.apereo.org/cas/protocol/logout"
Location="urn:mace:shibboleth:profile:CAS:logout"/>
<AssertionConsumerService Binding="https://www.apereo.org/cas/protocol/login" Location="https//sp.example.org/"
index="1"/>
</SPSSODescriptor>
</EntityDescriptor>
Create a much larger CAS metadata entry
xml = SmeeGen.cas!(
"https://example.com/cas",
service_urls: ["https://example.com/secure", "https://example.com/admin"],
proxy_urls: ["https://whatever.org/proxy"],
fragment: false,
id: "1001",
valid_until: expires_at,
cache_duration: duration,
proxy_keys: [cert],
displayname: "Test XML metadata",
information_url: "https://example.com/info",
description: "Just testing things",
privacy_url: "https://example.com/privacy_policy",
privacy_urls: %{
"fr" => "https://example.com/privacy_policy_fr"
},
keywords: %{
"en" => ["one", "two", "something else"]
},
logos: [[url: "https://example.com/logo.png", width: 50, height: 50]],
contacts: [
[
company: "Example Ltd",
email: "security@example.com",
surname: "Security",
givenname: "Security",
phone: "0161 496 0001",
type: :sirtfi
],
[
company: "Example Ltd",
email: "support@example.com",
surname: "Support",
givenname: "Online",
type: :technical
]
],
organization: [
name: "Example",
url: "https://example.com"
],
ras: true,
registration_authority: "https://regauth.example.org",
registration_instant: DateTime.utc_now(),
registration_policy_url: "https://blah.example.org"
)
outputs:
<EntityDescriptor entityID="https://example.com/cas" id="1001" validUntil="2026-07-29T16:07:46Z" cacheDuration="PT6H"
xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"
xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi">
<Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://regauth.example.org"
registrationInstant="2026-07-15T16:09:24Z">
<mdrpi:RegistrationPolicy xml:lang="en">https://blah.example.org</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
<mdattr:EntityAttributes>
<saml:Attribute Name="http://macedir.org/entity-category-support"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>http://refeds.org/category/research-and-scholarship</saml:AttributeValue>
</saml:Attribute>
</mdattr:EntityAttributes>
</Extensions>
<SPSSODescriptor protocolSupportEnumeration="https://www.apereo.org/cas/protocol">
<Extensions>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="en">Test XML metadata</mdui:DisplayName>
<mdui:Description xml:lang="en">Just testing things</mdui:Description>
<mdui:Keywords xml:lang="en">one two something+else</mdui:Keywords>
<mdui:InformationURL xml:lang="en">https://example.com/info</mdui:InformationURL>
<mdui:PrivacyStatementURL xml:lang="en">https://example.com/privacy_policy</mdui:PrivacyStatementURL>
<mdui:PrivacyStatementURL xml:lang="fr">https://example.com/privacy_policy_fr</mdui:PrivacyStatementURL>
<mdui:Logo xml:lang="en" width="50" height="50">https://example.com/logo.png</mdui:Logo>
</mdui:UIInfo>
</Extensions>
<KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDODCCAiCgAwIBAgIJAKpLQTw/WPXCMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNV
BAMTEWFscGhhLmV4YW1wbGUub3JnMB4XDTE4MDYxODE2NDE0NVoXDTE4MDcxODE2
NDE0NVowHDEaMBgGA1UEAxMRYWxwaGEuZXhhbXBsZS5vcmcwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDHSzRUcM0WBtAjR3P1vHYkaaATjNKTxbNHn3zS
3mLnEgukOVFrr+cRByKKUQQb8MIPkuvKrz3lnoCoOwlFMRPigtChjo3UJGTYEMY9
2SQQr24U6nE/3d2qFaf2PNIW1SinSjxbE1xeT0bdLcTZHUcE2yEfHKFhcgXIJprv
R1ceBJBvYYnATuPgUxMjq2ks4kXxG0nNlT13QwBfykBv6I1Wkkc06mEvkMzKNtzr
ayBK1PygVBNVMUQAFn7Tv6c28BtVLFE9SIKj+5ZcpuWkujVNJF1dYdNmfAz3PiuE
dPt2yl3t2r/v4CP+U8kBlQs6A83xYrA0MsHnUYOrfL3UTWtZAgMBAAGjfTB7MB0G
A1UdDgQWBBT/5yBm3mXtsYDvz11kTHsPVGeRcDBMBgNVHSMERTBDgBT/5yBm3mXt
sYDvz11kTHsPVGeRcKEgpB4wHDEaMBgGA1UEAxMRYWxwaGEuZXhhbXBsZS5vcmeC
CQCqS0E8P1j1wjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAb/o/M
mt/nSHOfcjnNJS/LpouaewkoWkQn+FaXZOOvHDYhWur+mHVDpjoszUfgrTX2npmL
e8Q94bHd+cQrJpZFiYRX8l0p7dAH5Q6Ya/AnHuzGeyQ9fXiDMSWcsg2INcWi7oL9
h9+V3idcSzgAo1b7+ESSToPj7OG8tgjEp2C9jy0IKEwoApuQtRzxD1XHZFBFwwuH
nIXWxgctJPU1C+1W9b4bkFSyEGz8/HM7D9feDHbn2AKuRgd99aaOY9D59topf2Zg
t5sUTWWl54eaF5qoXKY/jdl84Tnmo8GeUufCrS0T6YQGI1LTpicPbqf7zHihQTao
I1TQuJgghwPvPE9x
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<SingleLogoutService Binding="https://www.apereo.org/cas/protocol/logout"
Location="urn:mace:shibboleth:profile:CAS:logout"/>
<AssertionConsumerService Binding="https://www.apereo.org/cas/protocol/login" Location="https://example.com/secure"
index="1"/>
<AssertionConsumerService Binding="https://www.apereo.org/cas/protocol/login" Location="https://example.com/admin"
index="2"/>
<AssertionConsumerService Binding="https://www.apereo.org/cas/protocol/proxy" Location="https://whatever.org/proxy"
index="3"/>
</SPSSODescriptor>
<Organization>
<OrganizationName xml:lang="en">Example</OrganizationName>
<OrganizationDisplayName xml:lang="en">Example</OrganizationDisplayName>
<OrganizationURL xml:lang="en">https://example.com</OrganizationURL>
</Organization>
<ContactPerson contactType="other" xmlns:remd="https://refeds.org/metadata"
remd:contactType="http://refeds.org/metadata/contactType/security">
<Company>Example Ltd</Company>
<GivenName>Security</GivenName>
<SurName>Security</SurName>
<EmailAddress>mailto:security@example.com</EmailAddress>
<TelephoneNumber>0161 496 0001</TelephoneNumber>
</ContactPerson>
<ContactPerson contactType="technical">
<Company>Example Ltd</Company>
<GivenName>Online</GivenName>
<SurName>Support</SurName>
<EmailAddress>mailto:support@example.com</EmailAddress>
</ContactPerson>
</EntityDescriptor>
Validating the resulting XML with Smee
SmeeGen.cas!("https://sp.example.org")
|> Smee.Entity.new()
|> Smee.Entity.validate!()
Installation
If available in Hex, the package can be installed
by adding smee_gen to your list of dependencies in mix.exs:
def deps do
[
{:smee_gen, "~> 0.1"}
]
end
Warning
Please make sure you validate any metadata produced by SmeeGen before deploying it: this is an early release and it will absolutely contain mistakes and may produce invalid XML.
Alternatives
I normally list other projects that provide similar functionality but in this case I can't think of any. If you know of one please let me know and I will include it here.
Additional Information
SAML metadata standards
- Metadata for SAML
- SAML Metadata UI - MDUI
- Metadata Extensions for Registration and Publication Information
Shibboleth's SAML metadata profiles for CAS
Shibboleth's SAML metadata profiles for OIDC
Documentation
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/smee_gen.
Contributing
You can request new features by creating an issue, or submit a pull request with your contribution.
If you are comfortable working with Python but Smee's Elixir code is unfamiliar then this blog post may help: Elixir For Humans Who Know Python
Please do not submit any PRs or issues generated by "AI". This is a slop-free project and all mistakes are carefully hand-crafted by humans.
Copyright and License
Copyright (c) 2026 Digital Identity Ltd, UK
SmeeGen is Apache licensed.
Disclaimers
SmeeGen is not endorsed by The Shibboleth Foundation or any of the organizations mentioned within the code or data. The API may change considerably in the first few releases after 0.1.0.