Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix/6.1.3 #221

Merged
merged 8 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ plugins {
}


version "6.1.2"
version "6.1.3-SNAPSHOT"
group "org.grails.plugins"

apply plugin:"eclipse"
Expand Down Expand Up @@ -71,9 +71,9 @@ dependencies {
implementation "org.grails.plugins:scaffolding"
implementation "org.grails.plugins:gsp"
implementation 'commons-io:commons-io:2.6'
implementation "org.grails.plugins:ala-auth:5.1.1"
implementation 'org.pac4j:pac4j-core:5.3.1'
implementation 'org.pac4j:pac4j-http:5.3.1'
implementation "org.grails.plugins:ala-auth:$alaSecurityLibsVersion"
implementation "org.grails.plugins:ala-ws-security-plugin:$alaSecurityLibsVersion"
implementation "au.org.ala:userdetails-service-client:$alaSecurityLibsVersion"

console "org.grails:grails-console"
profile "org.grails.profiles:web-plugin"
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ org.gradle.parallel=true
#grailsWrapperVersion=1.0.0
#gradleWrapperVersion=5.0
assetPipelineVersion=3.4.7
seleniumVersion=4.0.0
seleniumVersion=4.2.0
webdriverBinariesVersion=2.6
seleniumSafariDriverVersion=4.0.0
org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xss2048k -Xmx1024M
exploded=true
enableClover=false
enableJacoco=true
alaSecurityLibsVersion=6.2.0
11 changes: 11 additions & 0 deletions grails-app/conf/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,14 @@ grails:
taglib: none
staticparts: none

userProfile:
userIdAttribute: "username"

---
environments:
test:
server:
port: "8087"
spring:
autoconfigure:
exclude: "au.org.ala.ws.security.AlaWsSecurityConfiguration"
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ModelService {
value = "'${value}'"
}
} else if(dataModel.name == 'recordedBy' && !value) {
value = "'${userInfoService.getCurrentUser()?.displayName?:''}'"
value = "'${userInfoService.getCurrentUserDisplayName()}'"
}
else if (value) {
value = JavaScriptCodec.ENCODER.encode(value)
Expand Down
122 changes: 80 additions & 42 deletions grails-app/services/au/org/ala/ecodata/forms/UserInfoService.groovy
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package au.org.ala.ecodata.forms

import au.org.ala.web.UserDetails
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.http.client.direct.DirectBearerAuthClient
import au.org.ala.ws.security.client.AlaOidcClient
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus

Expand Down Expand Up @@ -36,12 +37,46 @@ class UserInfoService {
@Autowired(required = false)
Config config
@Autowired(required = false)
DirectBearerAuthClient directBearerAuthClient
AlaOidcClient alaOidcClient

static String USER_NAME_HEADER_FIELD = "userName"
static String AUTH_KEY_HEADER_FIELD = "authKey"
static String AUTHORIZATION_HEADER_FIELD = "Authorization"

private static ThreadLocal<UserDetails> _currentUser = new ThreadLocal<UserDetails>()

String getCurrentUserDisplayName() {
getCurrentUser()?.displayName
}

UserDetails getCurrentUser() {
_currentUser.get()
}

/**
* This method gets called by a filter at the beginning of the request (if a userId parameter is on the URL)
* It sets the user details in a thread local for extraction by the audit service.
* @param userId
*/
UserDetails setCurrentUser() {
clearCurrentUser()
UserDetails userDetails = getCurrentUserFromSupportedMethods()

if (userDetails) {
_currentUser.set(userDetails)
} else {
log.warn("Failed to get user details! No details set on thread local.")
}

userDetails
}

def clearCurrentUser() {
if (_currentUser) {
_currentUser.remove()
}
}

/**
* Get User details for the given user name and auth key.
*
Expand All @@ -50,18 +85,13 @@ class UserInfoService {
* @return Map
*
**/
Map getUserFromAuthKey(String username, String key) {
UserDetails getUserFromAuthKey(String username, String key) {
String url = grailsApplication.config.getProperty('mobile.auth.check.url')
Map params = [userName: username, authKey: key]
def result = webService.doPostWithParams(url, params)

if (result.statusCode == HttpStatus.OK.value() && result.resp?.status == 'success') {
params = [userName: username]
url = grailsApplication.config.getProperty('userDetails.url') + "userDetails/getUserDetails"
result = webService.doPostWithParams(url, params)
if (result.statusCode == HttpStatus.OK.value() && result.resp) {
return ['displayName': "${result.resp.firstName} ${result.resp.lastName}", 'userName': result.resp.userName, 'userId': result.resp.userId]
}
return authService.getUserForEmailAddress(username, true)
} else {
log.error("Failed to get user details for parameters: ${params.toString()}")
log.error(result.toString())
Expand All @@ -73,57 +103,65 @@ class UserInfoService {
* @param authorizationHeader
* @return
*/
Map getUserFromJWT(String authorizationHeader = null) {
if((config == null) || (directBearerAuthClient == null))
UserDetails getUserFromJWT(String authorizationHeader = null) {
if((config == null) || (alaOidcClient == null))
return

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 = directBearerAuthClient.getCredentials(context, config.sessionStore)
if (optCredentials.isPresent()) {
Credentials credentials = optCredentials.get()
def optUserProfile = directBearerAuthClient.getUserProfile(credentials, context, config.sessionStore)
if (optUserProfile.isPresent()) {
def userProfile = optUserProfile.get()
return ['displayName': "${userProfile.getAttribute("given_name")} ${userProfile.getAttribute("family_name")}", 'userName': userProfile.getAttribute("email"), 'userId': userProfile.getAttribute("userid")]
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)
}
}
}
}
} catch (Throwable e) {
log.error("Failed to get user details from JWT", e)
return
}
}

/**
* Get details of the current user either from CAS or lookup to user details server.
* Authentication details are provide in header userName and authKey
* @return Map with following key
* ['displayName': "", 'userName': "", 'userId': ""]
* @return UserDetails
*/
def getCurrentUser() {
UserDetails getCurrentUserFromSupportedMethods() {
def user

// First, check if CAS can get logged in user details
def userDetails = authService.userDetails()
if (userDetails) {
user = ['displayName': "${userDetails.firstName} ${userDetails.lastName}", 'userName': userDetails.userName, 'userId': userDetails.userId]
}
user = userDetails?:null

// Second, check if request has headers to lookup user details.
if (!user) {
GrailsWebRequest request = GrailsWebRequest.lookup()
if (request) {
String authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD)
String username = request.getHeader(UserInfoService.USER_NAME_HEADER_FIELD)
String key = request.getHeader(UserInfoService.AUTH_KEY_HEADER_FIELD)

if (authorizationHeader) {
user = getUserFromJWT(authorizationHeader)
} else if (grailsApplication.config.getProperty("mobile.authKeyEnabled", Boolean) && username && key) {
user = getUserFromAuthKey(username, key)
try {
GrailsWebRequest request = GrailsWebRequest.lookup()
if (request) {
String authorizationHeader = request?.getHeader(AUTHORIZATION_HEADER_FIELD)
String username = request.getHeader(UserInfoService.USER_NAME_HEADER_FIELD)
String key = request.getHeader(UserInfoService.AUTH_KEY_HEADER_FIELD)

if (authorizationHeader) {
user = getUserFromJWT(authorizationHeader)
} else if (grailsApplication.config.getProperty("mobile.authKeyEnabled", Boolean) && username && key) {
user = getUserFromAuthKey(username, key)
}
}
} catch (Throwable e) {
log.error("Failed to get user details from JWT or API key", e)
}
}

Expand Down
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ module.exports = function (config) {
'type':"text",
check: {
global: {
lines: 48.1
lines: 47.6
}
}
},
Expand Down
Loading
Loading