Skip to content

Commit 9723299

Browse files
authored
Merge pull request #221 from AtlasOfLivingAustralia/hotfix/6.1.3
Hotfix/6.1.3
2 parents cc4195e + 2c07bdf commit 9723299

22 files changed

+1020
-674
lines changed

build.gradle

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ plugins {
1818
}
1919

2020

21-
version "6.1.2"
21+
version "6.1.3-SNAPSHOT"
2222
group "org.grails.plugins"
2323

2424
apply plugin:"eclipse"
@@ -71,9 +71,9 @@ dependencies {
7171
implementation "org.grails.plugins:scaffolding"
7272
implementation "org.grails.plugins:gsp"
7373
implementation 'commons-io:commons-io:2.6'
74-
implementation "org.grails.plugins:ala-auth:5.1.1"
75-
implementation 'org.pac4j:pac4j-core:5.3.1'
76-
implementation 'org.pac4j:pac4j-http:5.3.1'
74+
implementation "org.grails.plugins:ala-auth:$alaSecurityLibsVersion"
75+
implementation "org.grails.plugins:ala-ws-security-plugin:$alaSecurityLibsVersion"
76+
implementation "au.org.ala:userdetails-service-client:$alaSecurityLibsVersion"
7777

7878
console "org.grails:grails-console"
7979
profile "org.grails.profiles:web-plugin"

gradle.properties

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ org.gradle.parallel=true
77
#grailsWrapperVersion=1.0.0
88
#gradleWrapperVersion=5.0
99
assetPipelineVersion=3.4.7
10-
seleniumVersion=4.0.0
10+
seleniumVersion=4.2.0
1111
webdriverBinariesVersion=2.6
1212
seleniumSafariDriverVersion=4.0.0
1313
org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xss2048k -Xmx1024M
1414
exploded=true
1515
enableClover=false
1616
enableJacoco=true
17+
alaSecurityLibsVersion=6.2.0

grails-app/conf/application.yml

+11
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,14 @@ grails:
8888
taglib: none
8989
staticparts: none
9090

91+
userProfile:
92+
userIdAttribute: "username"
93+
94+
---
95+
environments:
96+
test:
97+
server:
98+
port: "8087"
99+
spring:
100+
autoconfigure:
101+
exclude: "au.org.ala.ws.security.AlaWsSecurityConfiguration"

grails-app/services/au/org/ala/ecodata/forms/ModelService.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class ModelService {
5353
value = "'${value}'"
5454
}
5555
} else if(dataModel.name == 'recordedBy' && !value) {
56-
value = "'${userInfoService.getCurrentUser()?.displayName?:''}'"
56+
value = "'${userInfoService.getCurrentUserDisplayName()}'"
5757
}
5858
else if (value) {
5959
value = JavaScriptCodec.ENCODER.encode(value)

grails-app/services/au/org/ala/ecodata/forms/UserInfoService.groovy

+80-42
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package au.org.ala.ecodata.forms
22

3+
import au.org.ala.web.UserDetails
34
import org.grails.web.servlet.mvc.GrailsWebRequest
45
import org.pac4j.core.config.Config
56
import org.pac4j.core.context.WebContext
67
import org.pac4j.core.credentials.Credentials
78
import org.pac4j.core.util.FindBest
89
import org.pac4j.jee.context.JEEContextFactory
9-
import org.pac4j.http.client.direct.DirectBearerAuthClient
10+
import au.org.ala.ws.security.client.AlaOidcClient
1011
import org.springframework.beans.factory.annotation.Autowired
1112
import org.springframework.http.HttpStatus
1213

@@ -36,12 +37,46 @@ class UserInfoService {
3637
@Autowired(required = false)
3738
Config config
3839
@Autowired(required = false)
39-
DirectBearerAuthClient directBearerAuthClient
40+
AlaOidcClient alaOidcClient
4041

4142
static String USER_NAME_HEADER_FIELD = "userName"
4243
static String AUTH_KEY_HEADER_FIELD = "authKey"
4344
static String AUTHORIZATION_HEADER_FIELD = "Authorization"
4445

46+
private static ThreadLocal<UserDetails> _currentUser = new ThreadLocal<UserDetails>()
47+
48+
String getCurrentUserDisplayName() {
49+
getCurrentUser()?.displayName
50+
}
51+
52+
UserDetails getCurrentUser() {
53+
_currentUser.get()
54+
}
55+
56+
/**
57+
* This method gets called by a filter at the beginning of the request (if a userId parameter is on the URL)
58+
* It sets the user details in a thread local for extraction by the audit service.
59+
* @param userId
60+
*/
61+
UserDetails setCurrentUser() {
62+
clearCurrentUser()
63+
UserDetails userDetails = getCurrentUserFromSupportedMethods()
64+
65+
if (userDetails) {
66+
_currentUser.set(userDetails)
67+
} else {
68+
log.warn("Failed to get user details! No details set on thread local.")
69+
}
70+
71+
userDetails
72+
}
73+
74+
def clearCurrentUser() {
75+
if (_currentUser) {
76+
_currentUser.remove()
77+
}
78+
}
79+
4580
/**
4681
* Get User details for the given user name and auth key.
4782
*
@@ -50,18 +85,13 @@ class UserInfoService {
5085
* @return Map
5186
*
5287
**/
53-
Map getUserFromAuthKey(String username, String key) {
88+
UserDetails getUserFromAuthKey(String username, String key) {
5489
String url = grailsApplication.config.getProperty('mobile.auth.check.url')
5590
Map params = [userName: username, authKey: key]
5691
def result = webService.doPostWithParams(url, params)
5792

5893
if (result.statusCode == HttpStatus.OK.value() && result.resp?.status == 'success') {
59-
params = [userName: username]
60-
url = grailsApplication.config.getProperty('userDetails.url') + "userDetails/getUserDetails"
61-
result = webService.doPostWithParams(url, params)
62-
if (result.statusCode == HttpStatus.OK.value() && result.resp) {
63-
return ['displayName': "${result.resp.firstName} ${result.resp.lastName}", 'userName': result.resp.userName, 'userId': result.resp.userId]
64-
}
94+
return authService.getUserForEmailAddress(username, true)
6595
} else {
6696
log.error("Failed to get user details for parameters: ${params.toString()}")
6797
log.error(result.toString())
@@ -73,57 +103,65 @@ class UserInfoService {
73103
* @param authorizationHeader
74104
* @return
75105
*/
76-
Map getUserFromJWT(String authorizationHeader = null) {
77-
if((config == null) || (directBearerAuthClient == null))
106+
UserDetails getUserFromJWT(String authorizationHeader = null) {
107+
if((config == null) || (alaOidcClient == null))
78108
return
79-
80-
GrailsWebRequest grailsWebRequest = GrailsWebRequest.lookup()
81-
HttpServletRequest request = grailsWebRequest.getCurrentRequest()
82-
HttpServletResponse response = grailsWebRequest.getCurrentResponse()
83-
if (!authorizationHeader)
84-
authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD)
85-
if (authorizationHeader?.startsWith("Bearer")) {
86-
final WebContext context = FindBest.webContextFactory(null, config, JEEContextFactory.INSTANCE).newContext(request, response)
87-
def optCredentials = directBearerAuthClient.getCredentials(context, config.sessionStore)
88-
if (optCredentials.isPresent()) {
89-
Credentials credentials = optCredentials.get()
90-
def optUserProfile = directBearerAuthClient.getUserProfile(credentials, context, config.sessionStore)
91-
if (optUserProfile.isPresent()) {
92-
def userProfile = optUserProfile.get()
93-
return ['displayName': "${userProfile.getAttribute("given_name")} ${userProfile.getAttribute("family_name")}", 'userName': userProfile.getAttribute("email"), 'userId': userProfile.getAttribute("userid")]
109+
try {
110+
GrailsWebRequest grailsWebRequest = GrailsWebRequest.lookup()
111+
HttpServletRequest request = grailsWebRequest.getCurrentRequest()
112+
HttpServletResponse response = grailsWebRequest.getCurrentResponse()
113+
if (!authorizationHeader)
114+
authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD)
115+
if (authorizationHeader?.startsWith("Bearer")) {
116+
final WebContext context = FindBest.webContextFactory(null, config, JEEContextFactory.INSTANCE).newContext(request, response)
117+
def optCredentials = alaOidcClient.getCredentials(context, config.sessionStore)
118+
if (optCredentials.isPresent()) {
119+
Credentials credentials = optCredentials.get()
120+
def optUserProfile = alaOidcClient.getUserProfile(credentials, context, config.sessionStore)
121+
if (optUserProfile.isPresent()) {
122+
def userProfile = optUserProfile.get()
123+
String userId = userProfile?.userId ?: userProfile?.getAttribute(grailsApplication.config.getProperty('userProfile.userIdAttribute'))
124+
if (userId) {
125+
return authService.getUserForUserId(userId)
126+
}
127+
}
94128
}
95129
}
130+
} catch (Throwable e) {
131+
log.error("Failed to get user details from JWT", e)
132+
return
96133
}
97134
}
98135

99136
/**
100137
* Get details of the current user either from CAS or lookup to user details server.
101138
* Authentication details are provide in header userName and authKey
102-
* @return Map with following key
103-
* ['displayName': "", 'userName': "", 'userId': ""]
139+
* @return UserDetails
104140
*/
105-
def getCurrentUser() {
141+
UserDetails getCurrentUserFromSupportedMethods() {
106142
def user
107143

108144
// First, check if CAS can get logged in user details
109145
def userDetails = authService.userDetails()
110-
if (userDetails) {
111-
user = ['displayName': "${userDetails.firstName} ${userDetails.lastName}", 'userName': userDetails.userName, 'userId': userDetails.userId]
112-
}
146+
user = userDetails?:null
113147

114148
// Second, check if request has headers to lookup user details.
115149
if (!user) {
116-
GrailsWebRequest request = GrailsWebRequest.lookup()
117-
if (request) {
118-
String authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD)
119-
String username = request.getHeader(UserInfoService.USER_NAME_HEADER_FIELD)
120-
String key = request.getHeader(UserInfoService.AUTH_KEY_HEADER_FIELD)
121-
122-
if (authorizationHeader) {
123-
user = getUserFromJWT(authorizationHeader)
124-
} else if (grailsApplication.config.getProperty("mobile.authKeyEnabled", Boolean) && username && key) {
125-
user = getUserFromAuthKey(username, key)
150+
try {
151+
GrailsWebRequest request = GrailsWebRequest.lookup()
152+
if (request) {
153+
String authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD)
154+
String username = request.getHeader(UserInfoService.USER_NAME_HEADER_FIELD)
155+
String key = request.getHeader(UserInfoService.AUTH_KEY_HEADER_FIELD)
156+
157+
if (authorizationHeader) {
158+
user = getUserFromJWT(authorizationHeader)
159+
} else if (grailsApplication.config.getProperty("mobile.authKeyEnabled", Boolean) && username && key) {
160+
user = getUserFromAuthKey(username, key)
161+
}
126162
}
163+
} catch (Throwable e) {
164+
log.error("Failed to get user details from JWT or API key", e)
127165
}
128166
}
129167

karma.conf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ module.exports = function (config) {
6868
'type':"text",
6969
check: {
7070
global: {
71-
lines: 48.1
71+
lines: 47.6
7272
}
7373
}
7474
},

0 commit comments

Comments
 (0)