Open RogelioCodes opened 1 year ago
Another thing I noticed was I will get a log that says I am authenticated even when I am not. I tested using an incognito tab. You can see "Authenticated: true;" towards the end of the line.
2022-11-15 20:11:38,904 DEBUG grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'grails.plugin.springsecurity.authentication.GrailsAnonymousAuthenticationToken@aad1a6c6: Principal: org.springframework.security.core.userdetails.User@dc730200: Username: __grails.anonymous.user__; Password: [PROTECTED]; Enabled: false; AccountNonExpired: false; credentialsNonExpired: false; AccountNonLocked: false; Granted Authorities: ROLE_ANONYMOUS; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: [REDACTED]; SessionId: 80ADD5CF5548217D9EA0858DBD4C40B8; Granted Authorities: ROLE_ANONYMOUS'
I don't really see a opensaml related error, you can turn that package off (org.opensaml.saml2) in the logback settings.
Your problem is very strange. It looks like the SAML login worked successfully but you are still not logged in. This either means the error is not being shown in the logs (are you sure you enabled the package 'org.grails.plugin.springsecurity.saml' and set it to debug level in your logback settings?) or there is some strange redirection happening or wrong URL that prevents you from logging in via the /saml/SSO Filter which should execute the SpringSamlUserDetailsService.
Here is what I expect to see:
2022-11-16 14:42:00.230 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Loading user - org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal@18955352
2022-11-16 14:42:00.240 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : getSamlUsername()
2022-11-16 14:42:00.240 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Username using attribute 'urn:oid:0.9.2342.19200300.100.1.1': <username>
2022-11-16 14:42:00.241 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Username <username>
2022-11-16 14:42:00.241 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Attempting to load UserClass with name: <package>.User
2022-11-16 14:42:00.242 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Loaded UserClass: class <package>.User
2022-11-16 14:42:00.332 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Generated User <username>
2022-11-16 14:42:00.343 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Determining Authorities for User(username:<username>)
2022-11-16 14:42:00.346 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Using role assignments from local database.
2022-11-16 14:42:00.455 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Added 2 role(s) from local database.
2022-11-16 14:42:00.457 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Using samlUserGroupAttribute: urn:oid:1.3.6.1.4.1.5923.1.1.1.1
2022-11-16 14:42:00.457 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Using samlGroups: [employee, member]
2022-11-16 14:42:00.458 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : User samlUserGroupToRoleMapping: [ROLE_EMPLOYEE:employee, ROLE_STUDENT:student]
2022-11-16 14:42:00.460 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Group Name From SAML: employee
2022-11-16 14:42:00.463 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Found Role
2022-11-16 14:42:00.463 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : getRole - param -> ROLE_EMPLOYEE
2022-11-16 14:42:00.487 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Where clause -> [authority:ROLE_EMPLOYEE]
2022-11-16 14:42:00.493 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Return Value from getRole Class-> class <package>.Role Value -> ROLE_EMPLOYEE
2022-11-16 14:42:00.493 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Found Authority Adding it
2022-11-16 14:42:00.494 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Group Name From SAML: member
2022-11-16 14:42:00.494 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : Returning Authorities with 3 Authorities added.
2022-11-16 14:42:00.494 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : User Class class <package>.User
2022-11-16 14:42:00.495 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : User - username <username>
2022-11-16 14:42:00.495 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : User - id null
2022-11-16 14:42:00.506 DEBUG --- [0.0-8009-exec-8] o.g.p.s.s.SpringSamlUserDetailsService : User Details org.grails.plugin.springsecurity.saml.SamlUserDetails [Username=<username>, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_ADMIN, ROLE_EMPLOYEE, ROLE_STUKO]]
...
2022-11-16 14:43:07.738 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Loading user - org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal@570bfa36
2022-11-16 14:43:07.738 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : getSamlUsername()
2022-11-16 14:43:07.739 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Username using attribute 'urn:oid:0.9.2342.19200300.100.1.1': <username>
2022-11-16 14:43:07.739 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Username <username>
2022-11-16 14:43:07.739 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Attempting to load UserClass with name: <package>.User
2022-11-16 14:43:07.739 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Loaded UserClass: class <package>.User
2022-11-16 14:43:07.740 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Generated User <username>
2022-11-16 14:43:07.745 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Determining Authorities for User(username:<username>)
2022-11-16 14:43:07.745 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Using role assignments from local database.
2022-11-16 14:43:07.761 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Added 2 role(s) from local database.
2022-11-16 14:43:07.763 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Using samlUserGroupAttribute: urn:oid:1.3.6.1.4.1.5923.1.1.1.1
2022-11-16 14:43:07.763 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Using samlGroups: [employee, member]
2022-11-16 14:43:07.763 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : User samlUserGroupToRoleMapping: [ROLE_EMPLOYEE:employee, ROLE_STUDENT:student]
2022-11-16 14:43:07.763 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Group Name From SAML: employee
2022-11-16 14:43:07.765 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Found Role
2022-11-16 14:43:07.765 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : getRole - param -> ROLE_EMPLOYEE
2022-11-16 14:43:07.766 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Where clause -> [authority:ROLE_EMPLOYEE]
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Return Value from getRole Class-> class <package>.Role Value -> ROLE_EMPLOYEE
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Found Authority Adding it
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Group Name From SAML: member
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : Returning Authorities with 3 Authorities added.
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : User Class class <package>.User
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : User - username <username>
2022-11-16 14:43:07.767 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : User - id null
2022-11-16 14:43:07.768 DEBUG --- [0.0-8009-exec-4] o.g.p.s.s.SpringSamlUserDetailsService : User Details org.grails.plugin.springsecurity.saml.SamlUserDetails [Username=<username>, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_ADMIN, ROLE_EMPLOYEE, ROLE_STUKO]]
Thank for the response. Here is my dependencies section of my build.gradle. @valentingoebel I thought logging was enabled for the plugin but now I am honestly not sure. I have not been working with java too long. How did you turn on logging? We have a logback.groovy, not logback.xml Could you tell me more about this /saml/SSO? Where should I be specifying that. Also how do you yourself handle logging in? Currently our home controller directs us to the default login controller. Should that default login controller work? It seems to be autogenerated by the plugin. We do get redirected to our login provider, and even asked for a 2 factor authentication push. Then we are redirected back to our default index.gsp.
Is there anything else we should be creating on our end? We have a secure controller as well which I will link down below. `
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
compile "org.springframework.boot:spring-boot-starter-logging"
compile "org.springframework.boot:spring-boot-autoconfigure"
compile "org.grails:grails-core"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-web-boot"
compile "org.grails:grails-logging"
compile "org.grails:grails-plugin-rest"
compile "org.grails:grails-plugin-databinding"
compile "org.grails:grails-plugin-i18n"
compile "org.grails:grails-plugin-services"
compile "org.grails:grails-plugin-url-mappings"
compile "org.grails:grails-plugin-interceptors"
compile "org.grails.plugins:cache"
compile "org.grails.plugins:async"
compile "org.grails.plugins:scaffolding"
compile "org.grails.plugins:events"
compile "org.grails.plugins:hibernate5"
compile "org.hibernate:hibernate-core:5.4.18.Final"
compile "org.grails.plugins:gsp"
compile 'org.grails.plugins:spring-security-core:4.0.3'
compile 'org.grails.plugins:spring-security-saml:4.0.2'
compile "org.springframework.boot:spring-boot-starter-security"
//compileOnly "io.micronaut:micronaut-inject-groovy"
console "org.grails:grails-console"
profile "org.grails.profiles:web"
runtime "org.glassfish.web:el-impl:2.1.2-b03"
runtime "com.h2database:h2"
runtime "org.apache.tomcat:tomcat-jdbc"
runtime "javax.xml.bind:jaxb-api:2.3.1"
runtime "com.bertramlabs.plugins:asset-pipeline-grails:3.2.4"
//testCompile "io.micronaut:micronaut-inject-groovy"
testCompile "org.grails:grails-gorm-testing-support"
testCompile "org.mockito:mockito-core"
testCompile "org.grails:grails-web-testing-support"
testCompile "org.grails.plugins:geb"
testCompile "org.seleniumhq.selenium:selenium-remote-driver:3.14.0"
testCompile "org.seleniumhq.selenium:selenium-api:3.14.0"
testCompile "org.seleniumhq.selenium:selenium-support:3.14.0"
testRuntime "org.seleniumhq.selenium:selenium-chrome-driver:3.14.0"
testRuntime "org.seleniumhq.selenium:selenium-firefox-driver:3.14.0"
}
`
Here is my logback.groovy `
import grails.util.BuildSettings
import grails.util.Environment
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.FileAppender
import static ch.qos.logback.classic.Level.INFO
import java.io.File
File logLevel = new File("/opt/tomcat/work/LOGLEVEL")
String LEVEL = "INFO"
if (logLevel.exists()) {
def LL = logLevel.readLines()
LEVEL = LL[0]
}
def targetDir = System.getProperty("LOG_PATH")
def targetFile = System.getProperty("LOG_FILE")
appender("FILE", FileAppender) {
file = "${targetDir}/${targetFile}"
encoder(PatternLayoutEncoder) {
pattern = "%date %level %logger - %msg%n"
}
}
appender("STDOUT", ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%msg%n"
}
}
//
// always have INFO
//
root(INFO, ["FILE", "STDOUT"])
if (LEVEL.equals("WARN")) {
root(INFO, ["FILE", "STDOUT"])
root(WARN, ["FILE", "STDOUT"])
}
if (LEVEL.equals("DEBUG")) {
root(INFO, ["FILE", "STDOUT"])
root(WARN, ["FILE", "STDOUT"])
root(DEBUG, ["FILE", "STDOUT"])
}
`
and my application.groovy
`
grails.plugin.springsecurity.userLookup.userDomainClassName = 'saml_grails_4.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'saml_grails_4.UserRole'
grails.plugin.springsecurity.authority.className = 'saml_grails_4.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/home/**', access: ['permitAll']],
[pattern: '/secure/**', 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']]
]
grails.plugin.springsecurity.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']
]
grails.plugin.springsecurity.debug.useFilter = true
grails.plugins.springsecurity.portMapper.httpsPort=8443
grails.app.context="/saml_grails_4"
grails.localServerURL = "https://localhost:8080${grails.app.context}"
grails.devServerURL = "https://itdmportal01.itdm.az.MYCOMPANY.com:8443/${grails.app.context}"
grails.prodServerURL = "https://itdmportal01.itdm.az.MYCOMPANY.com:8443/saml_grails_4"
grails.plugin.springsecurity.providerNames = ['samlAuthenticationProvider', 'daoAuthenticationProvider', 'anonymousAuthenticationProvider']
grails.plugin.springsecurity.saml.active = true
//grails.plugin.springsecurity.samluserAttributeMappings = [email: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', username: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress']
grails.plugin.springsecurity.saml.afterLoginUrl = '/'
grails.plugin.springsecurity.saml.afterLogoutUrl = '/'
grails.plugin.springsecurity.saml.responseSkew = 300
grails.plugin.springsecurity.saml.signatureAlgorithm = 'rsa-sha256'
grails.plugin.springsecurity.saml.digestAlgorithm = 'sha256'
grails.plugin.springsecurity.saml.userGroupAttribute = 'roles'
grails.plugin.springsecurity.saml.autoCreate.active = true //If you want the plugin to generate users in the DB as they are authenticated via SAML
grails.plugin.springsecurity.saml.autoCreate.key = 'id'
grails.plugin.springsecurity.saml.autoCreate.assignAuthorities = true //If you want the plugin to assign the authorities that come from the SAML message.
grails.plugin.springsecurity.saml.metadata.defaultIdp = 'http://signin.<mycompany>.com/exk2rvctc7x88VpZC697'
grails.plugin.springsecurity.saml.metadata.url = '/saml/metadata'
grails.plugin.springsecurity.saml.metadata.providers = ['http://signin.MYCOMPANY.com/exk2rvctc7x88VpZC697':'security/Idp_itdmportal01_metadata.xml']
grails.plugin.springsecurity.saml.metadata.sp.file = "security/sp_metadata.xml"
grails.plugin.springsecurity.saml.metadata.sp.defaults.local = false;
grails.plugin.springsecurity.saml.metadata.sp.defaults.entityId = 'https://itdmportal01.itdm.az.MYCOMPANY.com:8443/saml_grails_4'
grails.plugin.springsecurity.saml.metadata.sp.defaults.alias = 'itdmportal01';
grails.plugin.springsecurity.saml.metadata.sp.defaults.securityProfile = 'metaiop';
grails.plugin.springsecurity.saml.metadata.sp.defaults.signingKey = 'itdmportal01';
grails.plugin.springsecurity.saml.metadata.sp.defaults.encryptionKey = 'itdmportal01';
grails.plugin.springsecurity.saml.metadata.sp.defaults.tlsKey = 'itdmportal01';
grails.plugin.springsecurity.saml.metadata.sp.defaults.requireArtifactResolveSigned = true;
grails.plugin.springsecurity.saml.metadata.sp.defaults.requireLogoutRequestSigned = true;
grails.plugin.springsecurity.saml.metadata.sp.defaults.requireLogoutResponseSigned = false;
grails.plugin.springsecurity.saml.keyManager.storeFile = "classpath:security/itdmportal01.jks"
grails.plugin.springsecurity.saml.keyManager.storePass = '<password>'
grails.plugin.springsecurity.saml.keyManager.passwords = [itdmportal01:'<password>']
grails.plugin.springsecurity.saml.keyManager.defaultKey = 'itdmportal01'
`
Secure controller: `
package saml_grails_4
import groovy.lang.MissingPropertyException
import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*
import grails.plugin.springsecurity.annotation.Secured
import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.SpringSecurityService
import org.grails.plugin.springsecurity.saml.SpringSamlUserDetailsService;
import org.grails.plugin.springsecurity.saml.SamlSecurityService;
import org.springframework.beans.factory.annotation.Value
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.saml.SAMLCredential
import org.springframework.security.saml.userdetails.SAMLUserDetailsService
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
class SecureController {
static allowedMethods = [saml_grails_4: 'POST']
SpringSecurityService springSecurityService
SamlSecurityService samlSecurityService
SpringSamlUserDetailsService springSamlUserDetailsService
@Secured("hasAnyRole('ROLE_ADMIN', 'ROLE_ANONYMOUS')")
def index() {
println "SECURE ACCESS ONLY"
println "springSecurityService.Authentication: ${springSecurityService.authentication}"
println "samlSecurityService: ${samlSecurityService.getCurrentUser()}"
springSecurityService.principal
println "INSIDE SOMEMETHOD"
// springSamlUserDetailsService.load
println(springSecurityService.principal)
def username_test = springSecurityService.principal.getUsername()
println "INSIDE SOMEMETHOD2"
println(username_test)
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof AnonymousAuthenticationToken)) {
String currentUserName = authentication.getName();
render "Secure access only... you are authenticated: ${currentUsername}"
} else {
render "THERE IS NO USER"
}
render "Secure access only: ${springSecurityService.principal}"
}
@Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def startSAML() {
println "INSIDE START SAML"
session["sessid"] = params["sessid"]
session["templateid"] = params["temid"]
println("session[sessid] ${session["sessid"]} ")
println("session[templateid] = ${params["temid"]}")
redirect(actionName: "index")
}
@Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def saml_grails_4() {
def samlResponse = params["SAMLResponse"]
def sess = ""
def token = ""
println "SAMLRESPONSE:"
println samlResponse
println "BASEURL:"
def baseurl = grailsApplication.config.getProperty('grails.prodServerURL')
println baseurl
}
}
`
Our index.gsp is the default index.gsp that gets generated when you run grails-create-app
.
The only difference we made is that we added this line:
< href="https://itdmportal01.itdm.az.mycompany.com:8443/saml_grails_4/secure/startSAML"> <g:message code='register.label'/></A>
Which triggers our startSAML function inside of our secure controller. We have tried logging in using both that link and the link to the login controller. Neither seem to give us any success.
I did add in the SamlSecurityServices.groovy and SpringSamlUserDetails.groovy into our services folder to add in some extra print statements, but I have not been able to decipher what is going on. I definitely do not see anything close to the logs you mentioned.
If you have any other possible pointers please reach out and thanks a ton for taking the time to respond. We have been trying everything to get this to work.
The SAMLEntryPoint Filter uses springsecurity.auth.loginFormUrl=/login/auth. If you go to that path it should initiate SSO Login. If you want to manually specify your own path you can overwrite the bean in resources.groovy. The following configuration lets you use local login in development (optional SAML at /saml/auth) and test but forces SAML in every other environment.
resources.groovy
samlEntryPoint(SAMLEntryPoint) {
switch(Environment.current) {
case Environment.DEVELOPMENT:
filterProcessesUrl = '/saml/auth'
break
default:
filterProcessesUrl = '/login/auth'
break
}
defaultProfileOptions = ref('webProfileOptions')
}
Add this to your logback.groovy
logger 'org.grails.plugin.springsecurity.saml', DEBUG, ['STDOUT'], false
logger 'org.springframework.security.saml', DEBUG, ['STDOUT'], false
If you don't see any logs and never enter SpringSamlUserDetails then I don't know. You would have to use a debugger (in Eclipse or IntelliJ) and step through SamlEntryPoint/SAMLProcessingFilter (set a breakpoint in doFilter) until you find your problem.
Also, it shouldn't make a huge difference but try out version 4.0.3. It has a minor fix if you want to configure autoCreate.active=false.
We were able to get past many of our issues thanks to your help. One last question - currently we have our user attribute mappings set to grab an email but it seems to not be added to our SamlUserDetails. I am under the impression that setting the grails.plugin.springsecurity.samluserAttributeMappings should allow us to grab an email from the response that we get from our idp. Is there anything else we have to do to get this added to our userDetails? Please let me know, thanks @valentingoebel
grails.plugin.springsecurity.samluserAttributeMappings = [ emailAddress:'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified' ]
Here is what our saml response looks like `
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id7428569942196580287769288" IssueInstant="2022-11-17T22:04:39.840Z" Version="2.0">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://signin.mycompany.com/exk2rvctc7x88VpZC697</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">rcordova</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="a4facj1g0adddbaa27eic466jie64ef" NotOnOrAfter="2022-11-17T22:09:39.841Z" Recipient="https://itdmportal01.itdm.az.company.com:8443/saml_grails_4/saml/SSO"></saml2:SubjectConfirmationData>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2022-11-17T21:59:39.841Z" NotOnOrAfter="2022-11-17T22:09:39.841Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://itdmportal01.itdm.az.mycompany.com:8443/saml_grails_4</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2022-11-17T22:04:39.364Z" SessionIndex="a4facj1g0adddbaa27eic466jie64ef">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute Name="emailAddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">user@company.com
</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="username" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">sample_username
</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
`
You have to add the SAML attributes to your User.groovy class (specified in grails.plugin.springsecurity.userLookup.userDomainClassName = 'saml_grails_4.User).
class User implements Serializable{
...
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
String emailAddress
....
}
The plugin will fill those attributes automatically. You can then access it in any controller via principal.emailAddress.
we have tried defining that @valentingoebel but it seems to always break on insert. One thing we noticed is the samlAttributes always come back as null. Could it be that our samluserAttributeMapping is configured incorrectly?
`
Static SQL for entity: saml_grails_4.User
Version select: select version from user where id =?
Snapshot select: select user_.id, user_.version as version2_2_, user_.password_expired as password3_2_, user_.username as username4_2_, user_.emailaddress as emailadd5_2_, user_.account_locked as account_6_2_, user_.`password` as password7_2_, user_.account_expired as account_8_2_, user_.enabled as enabled9_2_ from user user_ where user_.id=?
Insert 0: insert into user (version, password_expired, username, emailaddress, account_locked, `password`, account_expired, enabled, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Update 0: update user set version=?, password_expired=?, username=?, emailaddress=?, account_locked=?, `password`=?, account_expired=?, enabled=? where id=? and version=?
Delete 0: delete from user where id=? and version=?
Identity insert: insert into user (version, password_expired, username, emailaddress, account_locked, `password`, account_expired, enabled) values (?, ?, ?, ?, ?, ?, ?, ?)
Adding QuerySpace : uid = <gen:0> -> org.hibernate.loader.plan.build.internal.spaces.EntityQuerySpaceImpl@5bc09b21]
Visiting attribute path : version
Visiting attribute path : passwordExpired
Visiting attribute path : username
Visiting attribute path : emailaddress
Visiting attribute path : accountLocked
Visiting attribute path : password
Visiting attribute path : accountExpired
Visiting attribute path : enabled
`
also our user.groovy @valentingoebel `
package saml_grails_4
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable {
private static final long serialVersionUID = 1
String username
String password
String emailaddress //Added by bolo
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set<Role> getAuthorities() {
(UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
}
static constraints = {
password nullable: false, blank: false, password: true
username nullable: false, blank: false, unique: true
}
static mapping = {
password column: '`password`'
}
}
`
It took me a long time to notice but did you misspell the configuration setting?
grails.plugin.springsecurity.samluserAttributeMappings
is supposed to be grails.plugin.springsecurity.saml.userAttributeMappings
(saml DOT userAttributeMappings).
Your saml response looks fine so the IDP is doing everything correctly. The User class is also correct.
Hello. I am trying to get the user information to print but I am not sure if the users are just being logged in as an anonymous user. In the logs we see that authentication is successful, but cannot get the user information to print. Here is my secureController:
| Grails Version: 4.0.3 | JVM Version: 1.8.0_292 `
`
And here are some logs:
`
` I cannot figure out if the user is actually being authenticated or if I am just getting an anonymous login