Closed jrAtAustin closed 3 years ago
"IDPSSODescriptor wasn't found" usually means the metadata for the IDP could not be found. It's usually a sign that you are not close to a properly working configuration because an insufficient configuration will usually cause the initialization of the plugin to fail with a visible error message but in your logs the application has started successfully and all that's left is going through the SAML login process.
It looks to me like the IDP Metadata is empty or the plugin is looking for the wrong entityID. Check your idpAzure.xml file and set the entityID for the IDP with grails.plugins.springsecurity.saml.metadata.defaultIdp. There should be an EntityDescriptor tag with the entityID and below it there is the IDPSSODescriptor tag that the plugin is looking for.
I did a manual test and if I change the defaultIdp to a wrong value I get the same error message. I think you just need to override defaultIdp and set it to whatever entityID is in your IDP metadata and then it will work.
@valentingoebel below is the configuration info, I removed the certificate info in the idpAzure.xml. Azure has a one year free signup if you would like to reproduce/test SSO integration with this Grails plugin.
grails {
plugin {
springsecurity {
// 5.4. Defining Secured Annotations
// https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#securedAnnotations
securityConfigType = "Annotation"
// 7.3. Registering Callback Closures
// https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#registeringCallbackClosures
useSecurityEventListener = true
onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
println("Event: ${e}")
}
// 10. Authentication Providers
// See https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#authentication
// for a description of creating a custom authentication provider
providerNames = [ 'samlAuthenticationProvider', 'daoAuthenticationProvider', 'anonymousAuthenticationProvider' ]
// 11. Custom UserDetailsService
// https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#userDetailsService
// TODO: We many need to create a custom UserDetailsService to extend login options.
// 16.1. Default Approach to Configuring Filter Chains
// https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#default-approach-to-configuring-filter-chains
//
// Added based on the Spring Security SAML plugin
// https://jeffwils.github.io/grails-spring-security-saml/
// 1. General Settings
active = true
afterLoginUrl = 'https://localhost:8443/'
afterLogoutUrl = 'http://localhost:8080/'
responseSkew = 300
metadata.url = '/saml/metadata'
// 2. Auto created settings
//saml.autoCreate.active = true
//saml.autoCreate.assignAuthorities=true
//
saml.metadata.sp.file = 'security/spMyApp.xml'
saml.metadata.providers = [ 'azureIdP': 'security/idpAzure.xml' ]
saml.metadata.defaultIdp = 'azureIdP'
saml.metadata.sp.defaults = [
local: true,
alias: 'test',
]
// Added by the Spring Security Core plugin:
userLookup.userDomainClassName = 'com.foo.gsscd.User'
userLookup.authorityJoinClassName = 'com.foo.gsscd.UserRole'
authority.className = 'com.foo.gsscd.Role'
controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']]
]
filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<EntityDescriptor ID="_229a2785-bd3f-48c3-a742-7c328c1a384b"
entityID="https://sts.windows.net/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/"
xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="#_229a2785-bd3f-48c3-a742-7c328c1a384b">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>bUuQs4yXgu3sGz3FxtSdX32LAzCVsZxIGle2LiRYU2A=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
...
</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>
...
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<RoleDescriptor xsi:type="fed:SecurityTokenServiceType"
protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>
...
</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<fed:ClaimTypesOffered>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Name</auth:DisplayName>
<auth:Description>The mutable display name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Subject</auth:DisplayName>
<auth:Description>An immutable, globally unique, non-reusable identifier of the user that is unique to
the application for which a token is issued.
</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Given Name</auth:DisplayName>
<auth:Description>First name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Surname</auth:DisplayName>
<auth:Description>Last name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/displayname"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Display Name</auth:DisplayName>
<auth:Description>Display name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/nickname"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Nick Name</auth:DisplayName>
<auth:Description>Nick name of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Authentication Instant</auth:DisplayName>
<auth:Description>The time (UTC) when the user is authenticated to Windows Azure Active Directory.
</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Authentication Method</auth:DisplayName>
<auth:Description>The method that Windows Azure Active Directory uses to authenticate users.
</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/objectidentifier"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>ObjectIdentifier</auth:DisplayName>
<auth:Description>Primary identifier for the user in the directory. Immutable, globally unique,
non-reusable.
</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/tenantid"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>TenantId</auth:DisplayName>
<auth:Description>Identifier for the user's tenant.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/identityprovider"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>IdentityProvider</auth:DisplayName>
<auth:Description>Identity provider for the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Email</auth:DisplayName>
<auth:Description>Email address of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Groups</auth:DisplayName>
<auth:Description>Groups of the user.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/accesstoken"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External Access Token</auth:DisplayName>
<auth:Description>Access token issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External Access Token Expiration</auth:DisplayName>
<auth:Description>UTC expiration time of access token issued by external identity provider.
</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/identity/claims/openid2_id"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>External OpenID 2.0 Identifier</auth:DisplayName>
<auth:Description>OpenID 2.0 identifier issued by external identity provider.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/claims/groups.link"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>GroupsOverageClaim</auth:DisplayName>
<auth:Description>Issued when number of user's group claims exceeds return limit.</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>Role Claim</auth:DisplayName>
<auth:Description>Roles that the user or Service Principal is attached to</auth:Description>
</auth:ClaimType>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity/claims/wids"
xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:DisplayName>RoleTemplate Id Claim</auth:DisplayName>
<auth:Description>Role template id of the Built-in Directory Roles that the user is a member of
</auth:Description>
</auth:ClaimType>
</fed:ClaimTypesOffered>
<fed:SecurityTokenServiceEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:SecurityTokenServiceEndpoint>
<fed:PassiveRequestorEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
<RoleDescriptor xsi:type="fed:ApplicationServiceType"
protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>
...
</X509Data>
</KeyInfo>
</KeyDescriptor>
<fed:TargetScopes>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://sts.windows.net/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/</wsa:Address>
</wsa:EndpointReference>
</fed:TargetScopes>
<fed:ApplicationServiceEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:ApplicationServiceEndpoint>
<fed:PassiveRequestorEndpoint>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/wsfed</wsa:Address>
</wsa:EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>
...
</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/saml2"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/saml2"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://login.microsoftonline.com/aXaXXXXe-b0XX-XXab-bXXX-XeXfXeXXfXcX/saml2"/>
</IDPSSODescriptor>
</EntityDescriptor>
@valentingoebel I changed saml.metadata.defaultIdp = 'azureIdP'
to the entityID in my IDP metadata and that got me past this issue. The examples I have seen show the providers key (saml.metadata.providers = [ 'azureIdP': 'security/idpAzure.xml' ]
) as the defaultIdp value.
I created a simple test app to test integrating Grails 3.3.11 with Azure Active Directory SAML SSO using the Spring Security SAML plugin. After configuring Azure and my Grails app I was redirected to the Azure login page where I logged in successfully. Azure sent my Grails app a successful assertion. When my Grails app try's to lookup the Azure IdP metadata in CachingMetadataManager.basicMetadataCache it finds the IdP alias in the metadata map but the value is null. The SP alias is in the same map but contains a non null value. It seems like the keys are set for the SP and IdP in CachingMetadataManager.basicMetadataCache but the value is not set for the IdP. Does anyone know if this is a configuration issue on my part or a bug in the plugin or spring security libraries?