From 0bcae505177006476c484bfe3ec24305fef55b84 Mon Sep 17 00:00:00 2001 From: chrisala Date: Tue, 28 Jan 2025 10:58:19 +1100 Subject: [PATCH 1/7] Updates to support new ala-security-project version/ java17 #1058 --- .github/workflows/build.yml | 9 +-- build.gradle | 4 +- gradle.properties | 5 +- grails-app/conf/application.groovy | 5 ++ .../au/org/ala/ecodata/UserService.groovy | 79 +++++++++---------- .../groovy/au/org/ala/ecodata/IniReader.java | 8 +- .../ecodata/metadata/SpeciesUrlGetter.groovy | 2 +- 7 files changed, 56 insertions(+), 56 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f0ba78b6d..b7a739f81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,6 @@ name: ecodata build on: push: branches: - - grails5java11 - dev - master - feature/** @@ -20,10 +19,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '17' distribution: 'adopt' - name: Validate Gradle wrapper @@ -31,7 +30,7 @@ jobs: - name: Install and start elasticsearch run: | - curl https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.16.3-amd64.deb -o elasticsearch.deb + curl https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.27-amd64.deb -o elasticsearch.deb sudo dpkg -i --force-confnew elasticsearch.deb sudo chown -R elasticsearch:elasticsearch /etc/default/elasticsearch sudo sh -c 'echo ES_JAVA_OPTS=\"-Xmx1g -Xms1g\" >> /etc/default/elasticsearch' @@ -40,7 +39,7 @@ jobs: - name: Install and start mongodb uses: supercharge/mongodb-github-action@1.7.0 with: - mongodb-version: '5.0' + mongodb-version: '8.0' - name: Build and run jacoco coverage report with Gradle uses: gradle/gradle-build-action@v2.4.2 diff --git a/build.gradle b/build.gradle index fb1837b2b..0830ca763 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ plugins { id "com.gorylenko.gradle-git-properties" version "2.4.1" } -version "5.2-SNAPSHOT" +version "$ecodataVersion" group "au.org.ala" description "Ecodata" @@ -38,7 +38,7 @@ if (Boolean.valueOf(enableJacoco)) { } sourceCompatibility = '11' -targetCompatibility = '11' +targetCompatibility = '17' apply from: "${project.projectDir}/gradle/publish.gradle" diff --git a/gradle.properties b/gradle.properties index c05270c1b..98f994e48 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,5 @@ -grailsVersion=6.2.0 +ecodataVersion=5.2-java17-SNAPSHOT +grailsVersion=6.2.3 grailsGradlePluginVersion=6.1.2 gormVersion=8.1.2 @@ -6,7 +7,7 @@ gormMongoVersion=8.2.0 grailsViewsVersion=2.3.2 assetPipelineVersion=4.3.0 elasticsearchVersion=7.17.21 -alaSecurityLibsVersion=6.3.0 +alaSecurityLibsVersion=6.4.0-SNAPSHOT #22.x+ causes issues with mongo / GORM javax.validation.spi, might need grails 5 geoToolsVersion=21.5 #jtsVersion must match the geotools version diff --git a/grails-app/conf/application.groovy b/grails-app/conf/application.groovy index f920c50ac..c4cc4e4ef 100644 --- a/grails-app/conf/application.groovy +++ b/grails-app/conf/application.groovy @@ -610,12 +610,17 @@ security { requiredScopes = [] connectTimeoutMs = 20000 readTimeoutMs = 20000 + callUserInfoEndpoint = false + alaUseridClaim = "username" + userIdClaim = "username" } } webservice.jwt = false webservice['jwt-scopes'] = "ala/internal users/read ala/attrs" webservice['client-id']='changeMe' webservice['client-secret'] = 'changeMe' +webservice['callUserInfoEndpoint'] = false + grails.gorm.graphql.browser = true diff --git a/grails-app/services/au/org/ala/ecodata/UserService.groovy b/grails-app/services/au/org/ala/ecodata/UserService.groovy index 82c218f51..b496bae74 100644 --- a/grails-app/services/au/org/ala/ecodata/UserService.groovy +++ b/grails-app/services/au/org/ala/ecodata/UserService.groovy @@ -2,14 +2,15 @@ package au.org.ala.ecodata import au.org.ala.userdetails.UserDetailsClient import au.org.ala.web.AuthService -import au.org.ala.ws.security.client.AlaOidcClient +import au.org.ala.ws.security.profile.AlaM2MUserProfile import grails.core.GrailsApplication import org.grails.web.servlet.mvc.GrailsWebRequest import org.pac4j.core.config.Config -import org.pac4j.core.context.WebContext -import org.pac4j.core.credentials.Credentials -import org.pac4j.core.util.FindBest -import org.pac4j.jee.context.JEEContextFactory +import org.pac4j.core.context.WebContextFactory +import org.pac4j.core.context.session.SessionStoreFactory +import org.pac4j.core.profile.UserProfile +import org.pac4j.core.profile.factory.ProfileManagerFactory +import org.pac4j.jee.context.JEEFrameworkParameters import org.springframework.beans.factory.annotation.Autowired import javax.servlet.http.HttpServletRequest @@ -25,8 +26,15 @@ class UserService { UserDetailsClient userDetailsClient @Autowired(required = false) Config config + + @Autowired(required = false) + WebContextFactory webContextFactory + @Autowired(required = false) - AlaOidcClient alaOidcClient + SessionStoreFactory sessionStoreFactory + + @Autowired(required = false) + ProfileManagerFactory profileManagerFactory /** Limit to the maximum number of Users returned by queries */ static final int MAX_QUERY_RESULT_SIZE = 1000 @@ -179,55 +187,42 @@ class UserService { } - /** - * Get user from JWT. - * @param authorizationHeader - * @return - */ - au.org.ala.web.UserDetails getUserFromJWT(String authorizationHeader = null) { - if((config == null) || (alaOidcClient == null)) - return - try { - GrailsWebRequest grailsWebRequest = GrailsWebRequest.lookup() - HttpServletRequest request = grailsWebRequest.getCurrentRequest() - HttpServletResponse response = grailsWebRequest.getCurrentResponse() - if (!authorizationHeader) - authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD) - if (authorizationHeader?.startsWith("Bearer")) { - final WebContext context = FindBest.webContextFactory(null, config, JEEContextFactory.INSTANCE).newContext(request, response) - def optCredentials = alaOidcClient.getCredentials(context, config.sessionStore) - if (optCredentials.isPresent()) { - Credentials credentials = optCredentials.get() - def optUserProfile = alaOidcClient.getUserProfile(credentials, context, config.sessionStore) - if (optUserProfile.isPresent()) { - def userProfile = optUserProfile.get() - String userId = userProfile?.userId ?: userProfile?.getAttribute(grailsApplication.config.getProperty('userProfile.userIdAttribute')) - if (userId) { - return authService.getUserForUserId(userId) - } - } - } + private String getUserIdFromPac4jProfile(HttpServletRequest request, HttpServletResponse response) { + // A simpler alternative here could be to check for the existence of the + // pac4j http request wrapper and pull the profile manager from it. + def params = new JEEFrameworkParameters(request, response) + def webContext = (this.webContextFactory ?: config.getWebContextFactory()).newContext(params) + def sessionStore = (this.sessionStoreFactory ?: config.getSessionStoreFactory()).newSessionStore(params) + def profileManager = (this.profileManagerFactory ?: config.getProfileManagerFactory()).apply(webContext, sessionStore) + Optional pac4jProfile = profileManager.getProfile() + + def profile = null + if (pac4jProfile.isPresent()) { + profile = pac4jProfile.get() + + if (profile instanceof AlaM2MUserProfile) { + return request.getHeader(AuditInterceptor.httpRequestHeaderForUserId) } - } catch (Throwable e) { - log.error("Failed to get user details from JWT", e) - return null } + return profile?.userId } def setUser() { - String userId GrailsWebRequest grailsWebRequest = GrailsWebRequest.lookup() HttpServletRequest request = grailsWebRequest.getCurrentRequest() + HttpServletResponse response = grailsWebRequest.getCurrentResponse() + + // First check if we've already saved the profile. def userDetails = request.getAttribute(UserDetails.REQUEST_USER_DETAILS_KEY) - if (userDetails) + if (userDetails) { return userDetails + } - // userId is set from either the request param userId or failing that it tries to get it from - // the UserPrincipal (assumes ecodata is being accessed directly via admin page) - userId = getUserFromJWT()?.userId ?: authService.getUserId() ?: request.getHeader(AuditInterceptor.httpRequestHeaderForUserId) + String userId = getUserIdFromPac4jProfile(request, response) if (userId) { + log.debug("Setting current user to ${userId}") userDetails = setCurrentUser(userId) if (userDetails) { // We set the current user details in the request scope because diff --git a/src/main/groovy/au/org/ala/ecodata/IniReader.java b/src/main/groovy/au/org/ala/ecodata/IniReader.java index d1c49508b..1f28e3b89 100644 --- a/src/main/groovy/au/org/ala/ecodata/IniReader.java +++ b/src/main/groovy/au/org/ala/ecodata/IniReader.java @@ -156,13 +156,13 @@ public int getIntegerValue(String section, String key) { */ public double getDoubleValue(String section, String key) { String str = document.get(section + "\\" + key); - Double ret; + double ret; try { - ret = new Double(str); + ret = Double.parseDouble(str); } catch (Exception e) { - ret = new Double(0); + ret = 0d; } - return ret.doubleValue(); + return ret; } /** diff --git a/src/main/groovy/au/org/ala/ecodata/metadata/SpeciesUrlGetter.groovy b/src/main/groovy/au/org/ala/ecodata/metadata/SpeciesUrlGetter.groovy index 89a7dffc1..0205f8791 100644 --- a/src/main/groovy/au/org/ala/ecodata/metadata/SpeciesUrlGetter.groovy +++ b/src/main/groovy/au/org/ala/ecodata/metadata/SpeciesUrlGetter.groovy @@ -3,7 +3,7 @@ package au.org.ala.ecodata.metadata import pl.touk.excel.export.getters.Getter import au.org.ala.ecodata.Record -class SpeciesUrlGetter extends OutputDataGetter implements Getter { +class SpeciesUrlGetter extends OutputDataGetter { String biePrefix SpeciesUrlGetter(String propertyName, Map dataNode, Map documentMap, TimeZone timeZone, String biePrefix) { super(propertyName, dataNode, documentMap, timeZone) From ab3b192beb4453803b8296587f8d727488d3548c Mon Sep 17 00:00:00 2001 From: chrisala Date: Tue, 28 Jan 2025 12:42:06 +1100 Subject: [PATCH 2/7] Simplified UserService.setUser and updated tests #1058 --- .../au/org/ala/ecodata/UserService.groovy | 37 +++++------- .../au/org/ala/ecodata/UserServiceSpec.groovy | 59 +++++++++++-------- 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/grails-app/services/au/org/ala/ecodata/UserService.groovy b/grails-app/services/au/org/ala/ecodata/UserService.groovy index b496bae74..5f2345f0a 100644 --- a/grails-app/services/au/org/ala/ecodata/UserService.groovy +++ b/grails-app/services/au/org/ala/ecodata/UserService.groovy @@ -8,9 +8,7 @@ import org.grails.web.servlet.mvc.GrailsWebRequest import org.pac4j.core.config.Config import org.pac4j.core.context.WebContextFactory import org.pac4j.core.context.session.SessionStoreFactory -import org.pac4j.core.profile.UserProfile import org.pac4j.core.profile.factory.ProfileManagerFactory -import org.pac4j.jee.context.JEEFrameworkParameters import org.springframework.beans.factory.annotation.Autowired import javax.servlet.http.HttpServletRequest @@ -187,30 +185,20 @@ class UserService { } - private String getUserIdFromPac4jProfile(HttpServletRequest request, HttpServletResponse response) { - // A simpler alternative here could be to check for the existence of the - // pac4j http request wrapper and pull the profile manager from it. - def params = new JEEFrameworkParameters(request, response) - def webContext = (this.webContextFactory ?: config.getWebContextFactory()).newContext(params) - def sessionStore = (this.sessionStoreFactory ?: config.getSessionStoreFactory()).newSessionStore(params) - def profileManager = (this.profileManagerFactory ?: config.getProfileManagerFactory()).apply(webContext, sessionStore) - Optional pac4jProfile = profileManager.getProfile() + private static String checkForDelegatedUserId(HttpServletRequest request) { + // When BioCollect or MERIT calls ecodata, they use a M2M access token which is able to be identified via + // the profile type. We can then trust the userId header to be the user MERIT or BioCollect is representing. + def principal = request.getUserPrincipal() - def profile = null - if (pac4jProfile.isPresent()) { - profile = pac4jProfile.get() - - if (profile instanceof AlaM2MUserProfile) { - return request.getHeader(AuditInterceptor.httpRequestHeaderForUserId) - } + if (principal && principal instanceof AlaM2MUserProfile) { + return request.getHeader(AuditInterceptor.httpRequestHeaderForUserId) } - return profile?.userId + return null } def setUser() { GrailsWebRequest grailsWebRequest = GrailsWebRequest.lookup() HttpServletRequest request = grailsWebRequest.getCurrentRequest() - HttpServletResponse response = grailsWebRequest.getCurrentResponse() // First check if we've already saved the profile. def userDetails = request.getAttribute(UserDetails.REQUEST_USER_DETAILS_KEY) @@ -218,11 +206,18 @@ class UserService { if (userDetails) { return userDetails } + // If the user has logged in interactively or supplies a bearer token which identifies the user + // (e.g. the Monitor app passes the user token) the authService will be able to resolve the user from the token. + String userId = authService.getUserId() - String userId = getUserIdFromPac4jProfile(request, response) - + // Otherwise, if the token is an ALA M2M token from MERIT or BioCollect, we can obtain the userId + // from a separate header. + if (!userId) { + userId = checkForDelegatedUserId(request) + } if (userId) { log.debug("Setting current user to ${userId}") + userDetails = setCurrentUser(userId) if (userDetails) { // We set the current user details in the request scope because diff --git a/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy b/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy index cf97bad17..ca34e147a 100644 --- a/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy +++ b/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy @@ -1,15 +1,11 @@ package au.org.ala.ecodata import au.org.ala.web.AuthService -import au.org.ala.ws.security.client.AlaOidcClient -import au.org.ala.ws.security.profile.AlaOidcUserProfile +import au.org.ala.ws.security.profile.AlaM2MUserProfile import grails.test.mongodb.MongoSpec import grails.testing.services.ServiceUnitTest import grails.testing.web.GrailsWebUnitTest import org.pac4j.core.config.Config -import org.pac4j.core.credentials.AnonymousCredentials -import org.pac4j.core.credentials.Credentials -import org.pac4j.core.profile.UserProfile import spock.lang.Unroll /** @@ -20,7 +16,6 @@ class UserServiceSpec extends MongoSpec implements ServiceUnitTest, WebService webService = Mock(WebService) AuthService authService = Mock(AuthService) - AlaOidcClient alaOidcClient Config pack4jConfig def user @@ -43,6 +38,7 @@ class UserServiceSpec extends MongoSpec implements ServiceUnitTest, def cleanup() { User.findAll().each{it.delete(flush:true)} Hub.findAll().each{it.delete(flush:true)} + service.clearCurrentUser() } def "The recordLoginTime method requires a hubId and userId to be supplied"() { @@ -160,28 +156,45 @@ class UserServiceSpec extends MongoSpec implements ServiceUnitTest, "h1" | "2021-04-15T00:00:00Z" | "2021-05-01T00:00:00Z" | 0 } - void "getUserFromJWT returns user when Authorization header is passed"() { + void "The user service can identify the user using the authService and make it available on a ThreadLocal"() { + when: + service.setUser() + + then: + 1 * authService.getUserId() >> user.userId + 1 * authService.getUserForUserId(user.userId) >> userDetails + + UserService.currentUser() == userDetails + } + + void "The user service can identify an ALA M2M access token and identify the user from a request header"() { setup: - def result - alaOidcClient = GroovyMock([global: true], AlaOidcClient) - pack4jConfig = GroovyMock([global: true], Config) - service.alaOidcClient = alaOidcClient - service.config = pack4jConfig - AlaOidcUserProfile person = new AlaOidcUserProfile(user.userId) - Optional credentials = new Optional(AnonymousCredentials.INSTANCE) - Optional userProfile = new Optional(person) + AuditInterceptor.httpRequestHeaderForUserId = 'userId' + request.setUserPrincipal(new AlaM2MUserProfile('clientId', 'test', [])) when: - request.addHeader('Authorization', 'Bearer abcdef') - result = service.getUserFromJWT() + request.addHeader('userId', user.userId) + service.setUser() then: - alaOidcClient.getCredentials(*_) >> credentials - alaOidcClient.getUserProfile(*_) >> userProfile - authService.getUserForUserId(user.userId) >> userDetails - result.userName == user.userName - result.displayName == "${user.firstName} ${user.lastName}" - result.userId == user.userId + 1 * authService.getUserId() >> null + + 1 * authService.getUserForUserId(user.userId) >> userDetails + + UserService.currentUser() == userDetails + } + + void "The user service will not read the userId from the header if the caller isn't an ALA system"() { + when: + request.addHeader('userId', user.userId) + service.setUser() + + then: + 1 * authService.getUserId() >> null + 0 * authService.getUserDetailsById(_) + UserService.currentUser() == null + + } From 808d99ebeab6ecf3f53b6b186b7bf76c1569bc19 Mon Sep 17 00:00:00 2001 From: chrisala Date: Tue, 28 Jan 2025 15:58:42 +1100 Subject: [PATCH 3/7] Removed unused dependencies #1058 --- .../au/org/ala/ecodata/UserService.groovy | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/grails-app/services/au/org/ala/ecodata/UserService.groovy b/grails-app/services/au/org/ala/ecodata/UserService.groovy index 5f2345f0a..d2ab765d0 100644 --- a/grails-app/services/au/org/ala/ecodata/UserService.groovy +++ b/grails-app/services/au/org/ala/ecodata/UserService.groovy @@ -1,18 +1,11 @@ package au.org.ala.ecodata -import au.org.ala.userdetails.UserDetailsClient + import au.org.ala.web.AuthService import au.org.ala.ws.security.profile.AlaM2MUserProfile -import grails.core.GrailsApplication import org.grails.web.servlet.mvc.GrailsWebRequest -import org.pac4j.core.config.Config -import org.pac4j.core.context.WebContextFactory -import org.pac4j.core.context.session.SessionStoreFactory -import org.pac4j.core.profile.factory.ProfileManagerFactory -import org.springframework.beans.factory.annotation.Autowired import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse class UserService { @@ -20,19 +13,6 @@ class UserService { static String AUTHORIZATION_HEADER_FIELD = "Authorization" AuthService authService WebService webService - GrailsApplication grailsApplication - UserDetailsClient userDetailsClient - @Autowired(required = false) - Config config - - @Autowired(required = false) - WebContextFactory webContextFactory - - @Autowired(required = false) - SessionStoreFactory sessionStoreFactory - - @Autowired(required = false) - ProfileManagerFactory profileManagerFactory /** Limit to the maximum number of Users returned by queries */ static final int MAX_QUERY_RESULT_SIZE = 1000 From e0bde6f6c37abebe69d1899d5407445ade21a7bb Mon Sep 17 00:00:00 2001 From: chrisala Date: Wed, 29 Jan 2025 08:40:46 +1100 Subject: [PATCH 4/7] Removed dependency on ala auth implementation #1058 --- .../au/org/ala/ecodata/UserService.groovy | 20 ++++++++++++------- .../au/org/ala/ecodata/UserServiceSpec.groovy | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/grails-app/services/au/org/ala/ecodata/UserService.groovy b/grails-app/services/au/org/ala/ecodata/UserService.groovy index d2ab765d0..b52b39b8d 100644 --- a/grails-app/services/au/org/ala/ecodata/UserService.groovy +++ b/grails-app/services/au/org/ala/ecodata/UserService.groovy @@ -1,8 +1,7 @@ package au.org.ala.ecodata - import au.org.ala.web.AuthService -import au.org.ala.ws.security.profile.AlaM2MUserProfile +import grails.core.GrailsApplication import org.grails.web.servlet.mvc.GrailsWebRequest import javax.servlet.http.HttpServletRequest @@ -13,6 +12,8 @@ class UserService { static String AUTHORIZATION_HEADER_FIELD = "Authorization" AuthService authService WebService webService + GrailsApplication grailsApplication + /** Limit to the maximum number of Users returned by queries */ static final int MAX_QUERY_RESULT_SIZE = 1000 @@ -165,12 +166,17 @@ class UserService { } - private static String checkForDelegatedUserId(HttpServletRequest request) { - // When BioCollect or MERIT calls ecodata, they use a M2M access token which is able to be identified via - // the profile type. We can then trust the userId header to be the user MERIT or BioCollect is representing. - def principal = request.getUserPrincipal() + private String checkForDelegatedUserId(HttpServletRequest request) { + // When BioCollect or MERIT calls ecodata, they use a M2M access token which contains custom scopes to + // enable access to the ecodata API. + // We can trust the requests containing bearer tokens with this scope and extract the userId from a header. + String scope = grailsApplication.config.getProperty('app.readScope') + if (!scope) { + log.error("No read scope specified in config.") + return null + } - if (principal && principal instanceof AlaM2MUserProfile) { + if (request.isUserInRole(scope)) { return request.getHeader(AuditInterceptor.httpRequestHeaderForUserId) } return null diff --git a/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy b/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy index ca34e147a..de7de7c80 100644 --- a/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy +++ b/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy @@ -170,7 +170,7 @@ class UserServiceSpec extends MongoSpec implements ServiceUnitTest, void "The user service can identify an ALA M2M access token and identify the user from a request header"() { setup: AuditInterceptor.httpRequestHeaderForUserId = 'userId' - request.setUserPrincipal(new AlaM2MUserProfile('clientId', 'test', [])) + request.addUserRole("ecodata/read_test") when: request.addHeader('userId', user.userId) From fdaece90abff8f9f0292e5773a2ebc80f1135fe9 Mon Sep 17 00:00:00 2001 From: chrisala Date: Fri, 31 Jan 2025 12:15:00 +1100 Subject: [PATCH 5/7] Updated user check to work with CAS #1058 --- .../au/org/ala/ecodata/UserService.groovy | 15 +++++++++------ .../au/org/ala/ecodata/UserServiceSpec.groovy | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/grails-app/services/au/org/ala/ecodata/UserService.groovy b/grails-app/services/au/org/ala/ecodata/UserService.groovy index b52b39b8d..2413b9a10 100644 --- a/grails-app/services/au/org/ala/ecodata/UserService.groovy +++ b/grails-app/services/au/org/ala/ecodata/UserService.groovy @@ -192,14 +192,17 @@ class UserService { if (userDetails) { return userDetails } - // If the user has logged in interactively or supplies a bearer token which identifies the user - // (e.g. the Monitor app passes the user token) the authService will be able to resolve the user from the token. - String userId = authService.getUserId() - // Otherwise, if the token is an ALA M2M token from MERIT or BioCollect, we can obtain the userId - // from a separate header. + // if the token is an ALA M2M token from MERIT or BioCollect, we can obtain the userId + // from a separate header. This is the most common scenario as most calls to ecodata will fall into + // this category. + String userId = checkForDelegatedUserId(request) + + // Otherwise, if the user has logged in interactively or supplies a bearer token which identifies the user + // (e.g. the Monitor app passes the user token) the authService will be able to resolve the user from the token. + // If the OIDC provider is CAS, authService.getUser() will return the clientId, if it's Cognito, it will return null. if (!userId) { - userId = checkForDelegatedUserId(request) + userId = authService.getUserId() } if (userId) { log.debug("Setting current user to ${userId}") diff --git a/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy b/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy index de7de7c80..9d9ac1ee3 100644 --- a/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy +++ b/src/test/groovy/au/org/ala/ecodata/UserServiceSpec.groovy @@ -177,7 +177,7 @@ class UserServiceSpec extends MongoSpec implements ServiceUnitTest, service.setUser() then: - 1 * authService.getUserId() >> null + 0 * authService.getUserId() >> null 1 * authService.getUserForUserId(user.userId) >> userDetails From c2b053ea4456013f654c598e04cedc1a228bcfed Mon Sep 17 00:00:00 2001 From: chrisala Date: Mon, 3 Feb 2025 12:08:36 +1100 Subject: [PATCH 6/7] Bump travis to java17 #1058 --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9b74bf8f..9ca7eb283 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,11 @@ os: linux dist: bionic language: groovy jdk: - - openjdk11 + - openjdk17 branches: only: - master - dev - - hot-fix - /^feature\/.*$/ - /^hotfix\/.*$/ From 8a418add434a4c0203e9076a84c1ce7e86516ea7 Mon Sep 17 00:00:00 2001 From: chrisala Date: Wed, 12 Feb 2025 07:49:07 +1100 Subject: [PATCH 7/7] Check for clonable before calling clone for java17 #1058 --- .../services/au/org/ala/ecodata/ParatooService.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grails-app/services/au/org/ala/ecodata/ParatooService.groovy b/grails-app/services/au/org/ala/ecodata/ParatooService.groovy index 6a798eafe..5aecd0fbf 100644 --- a/grails-app/services/au/org/ala/ecodata/ParatooService.groovy +++ b/grails-app/services/au/org/ala/ecodata/ParatooService.groovy @@ -1059,10 +1059,10 @@ class ParatooService { cleanedDefinition << cleanSwaggerDefinition(value) } } else { - try { - cleanedDefinition = definition?.clone() + if (definition instanceof Cloneable) { + cleanedDefinition = definition.clone() } - catch (CloneNotSupportedException e) { + else { // if not cloneable, then it is a primitive type cleanedDefinition = definition }