Skip to content

Commit

Permalink
Refactor web services #141
Browse files Browse the repository at this point in the history
  • Loading branch information
yasima-csiro committed Dec 13, 2022
1 parent 86645b7 commit efde9b2
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 71 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ dependencies {

implementation "org.grails.plugins:ala-bootstrap3:4.1.0"
implementation "org.grails.plugins:ala-ws-plugin:3.1.1"
implementation "org.grails.plugins:ala-ws-security-plugin:4.3.3-SNAPSHOT"
implementation "org.grails.plugins:ala-auth:5.1.1"
implementation "org.grails.plugins:ala-ws-security-plugin:4.3.5-SNAPSHOT"
implementation "org.grails.plugins:ala-auth:5.2.0-CognitoLogoutFix-SNAPSHOT"
implementation "org.grails.plugins:ala-admin-plugin:2.3.0"

implementation 'dk.glasius:external-config:3.1.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class PropertyController extends BaseController {
name = "alaId",
in = QUERY,
description = "The user's ALA ID",
schema = @Schema(implementation = Long),
required = true
),
@Parameter(
Expand Down Expand Up @@ -100,14 +99,14 @@ class PropertyController extends BaseController {
@PreAuthorise(requiredScope = 'users/read')
def getProperty() {
String name = params.name
Long alaId = params.long('alaId')
String alaId = params.alaId
if (!name || !alaId) {
badRequest "name and alaId must be provided";
} else {
User user = userService.getUserById(alaId);
List props
if (user) {
props = profileService.getUserProperty(user, name);
props = userService.getCustomUserProperty(user, name)
render text: props as JSON, contentType: 'application/json'
} else {
notFound "Could not find user for id: ${alaId}";
Expand All @@ -130,7 +129,6 @@ class PropertyController extends BaseController {
name = "alaId",
in = QUERY,
description = "The user's ALA ID",
schema = @Schema(implementation = Long),
required = true
),
@Parameter(
Expand Down Expand Up @@ -178,15 +176,15 @@ class PropertyController extends BaseController {
def saveProperty(){
String name = params.name;
String value = params.value;
Long alaId = params.long('alaId');
String alaId = params.alaId
if (!name || !alaId) {
badRequest "name and alaId must be provided";
} else {
User user = userService.getUserById(alaId);
UserProperty property
def property
if (user) {
property = profileService.saveUserProperty(user, name, value);
if (property.hasErrors()) {
property = userService.saveCustomUserProperty(user, name, value);
if (!property) {
saveFailed()
} else {
render text: property as JSON, contentType: 'application/json'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ class RoleBasedInterceptor {
PreAuthorise pa = method.getAnnotation(PreAuthorise) ?: controllerClass.getAnnotation(PreAuthorise)
response.withFormat {
json {
if (!authorisedSystemService.isAuthorisedRequest(request, response, pa.requiredRole(), pa.requiredScope())) {
log.warn("Denying access to $actionName from remote addr: ${request.remoteAddr}, remote host: ${request.remoteHost}")
response.status = HttpStatus.SC_UNAUTHORIZED
render(['error': "Unauthorized"] as JSON)
try{
if (!authorisedSystemService.isAuthorisedRequest(request, response, pa.requiredRole(), pa.requiredScope())) {
log.warn("Denying access to $actionName from remote addr: ${request.remoteAddr}, remote host: ${request.remoteHost}")
response.status = HttpStatus.SC_UNAUTHORIZED
render(['error': "Unauthorized"] as JSON)

result = false
result = false
}
}
catch (Exception e){
response.sendError(HttpStatus.SC_UNAUTHORIZED, e.getMessage())
return false
}
}
'*' {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,20 @@ class UserDetailsController {
render(status: 401, text: 'q parameter is required')
}
def max = params.int('max', 10)
User.withStatelessSession { session ->
def c = User.createCriteria()
ScrollableResults results = c.scroll {
or {
ilike('userName', "%$q%")
ilike('email', "%$q%")
ilike('displayName', "%$q%")
}
maxResults(max)
def searchResults = userService.searchByUsernameOrEmail(q as String, max)
if(searchResults.results instanceof ScrollableResults) {
streamResults(null, searchResults.results, UserMarshaller.WITH_PROPERTIES_CONFIG)
}
else{
try {
JSON.use(UserMarshaller.WITH_PROPERTIES_CONFIG)
render searchResults.results as JSON
return
}finally {
JSON.use(null) // resets to default config
}
streamResults(session, results, UserMarshaller.WITH_PROPERTIES_CONFIG)
}

}

@Operation(
Expand All @@ -130,6 +132,12 @@ class UserDetailsController {
in = QUERY,
description = "Whether to include additional user properties or not",
required = false
),
@Parameter(
name = "cognitoNextToken",
in = QUERY,
description = "Cognito token to retrieve next set of results",
required = false
)
],
responses = [
Expand All @@ -152,36 +160,30 @@ class UserDetailsController {
def ids = params.list('id')
def roleName = params.get('role', 'ROLE_USER')
def includeProps = params.boolean('includeProps', false)
String cognitoNextToken = params.cognitoNextToken

def things = ids.groupBy { it.isLong() }
def userIds = things[false]
def numberIds = things[true]

// stream the results just in case someone requests ROLE_USER or something
User.withStatelessSession { session ->
Role role = Role.findByRole(roleName)
if (!role) {
response.sendError(404, "Role not found")
return
def searchResults = userService.findUsersByRole(roleName, numberIds, userIds, cognitoNextToken)
if(searchResults.error){
response.sendError(404, searchResults.error)
return
}
else{
if(searchResults.results instanceof ScrollableResults) {
streamResults(null, searchResults.results, includeProps ? UserMarshaller.WITH_PROPERTIES_CONFIG : 'default')
}

def c = User.createCriteria()
ScrollableResults results = c.scroll {
or {
if (numberIds) {
inList('id', numberIds*.toLong())
}
if (userIds) {
inList('userName', userIds)
inList('email', userIds)
}
}
userRoles {
eq("role", role)
else{
try {
JSON.use(includeProps ? UserMarshaller.WITH_PROPERTIES_CONFIG : 'default')
render searchResults as JSON
return
}finally {
JSON.use(null) // resets to default config
}
}

streamResults(session, results, includeProps ? UserMarshaller.WITH_PROPERTIES_CONFIG : 'default')
}
}

Expand Down Expand Up @@ -265,7 +267,7 @@ class UserDetailsController {
if (userName.isLong()) {
user = userService.getUserById(userName)
} else {
user = User.findByUserNameOrEmail(userName, userName)
user = userService.findByUserNameOrEmail(userName)
}
} else {
render status:400, text: "Missing parameter: userName"
Expand Down Expand Up @@ -414,24 +416,21 @@ class UserDetailsController {
if (req && req.userIds) {

try {
List<Long> idList = req.userIds.collect { userId -> userId as long }
List idList = req.userIds

def c = User.createCriteria()
def results = c.list() {
'in'("id", idList)
}
def results = userService.getUserDetailsFromIdList(idList)
String jsonConfig = includeProps ? UserMarshaller.WITH_PROPERTIES_CONFIG : null
try {

JSON.use(jsonConfig)

def resultsMap = [users:[:], invalidIds:[], success: true]
results.each { user ->
resultsMap.users[user.id] = user
resultsMap.users[user.userId] = user
}

idList.each {
if (!resultsMap.users[it]) {
if (!resultsMap.users[it.toString()]) {
resultsMap.invalidIds << it
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ class UserDetailsWebServicesInterceptor {
}

boolean before() {
if (!authorisedSystemService.isAuthorisedRequest(request, response, null, 'users/read')) {
log.warn("Denying access to $actionName from remote addr: ${request.remoteAddr}, remote host: ${request.remoteHost}")
response.sendError(HttpStatus.SC_UNAUTHORIZED)

try {
if (!authorisedSystemService.isAuthorisedRequest(request, response, null, 'users/read')) {
log.warn("Denying access to $actionName from remote addr: ${request.remoteAddr}, remote host: ${request.remoteHost}")
response.sendError(HttpStatus.SC_UNAUTHORIZED)

return false
}
return true
}
catch (Exception e){
response.sendError(HttpStatus.SC_UNAUTHORIZED, e.getMessage())
return false
}
return true
}

boolean after() { true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import org.pac4j.core.context.WebContext
import org.pac4j.core.profile.ProfileManager
import org.pac4j.core.profile.UserProfile
import org.pac4j.core.util.FindBest
import org.pac4j.http.client.direct.DirectBearerAuthClient
import au.org.ala.ws.security.client.AlaAuthClient
import org.pac4j.jee.context.JEEContextFactory
import org.springframework.beans.factory.annotation.Autowired

Expand All @@ -35,7 +35,7 @@ class AuthorisedSystemService {
@Autowired(required = false)
Config config
@Autowired(required = false)
DirectBearerAuthClient directBearerAuthClient
AlaAuthClient alaAuthClient

def isAuthorisedSystem(HttpServletRequest request){
def host = request.getRemoteAddr()
Expand All @@ -61,15 +61,15 @@ class AuthorisedSystemService {
ProfileManager profileManager = new ProfileManager(context, config.sessionStore)
profileManager.setConfig(config)

def credentials = directBearerAuthClient.getCredentials(context, config.sessionStore)
def credentials = alaAuthClient.getCredentials(context, config.sessionStore)
if (credentials.isPresent()) {
def profile = directBearerAuthClient.getUserProfile(credentials.get(), context, config.sessionStore)
def profile = alaAuthClient.getUserProfile(credentials.get(), context, config.sessionStore)
if (profile.isPresent()) {
def userProfile = profile.get()
profileManager.save(
directBearerAuthClient.getSaveProfileInSession(context, userProfile),
alaAuthClient.getSaveProfileInSession(context, userProfile),
userProfile,
directBearerAuthClient.isMultiProfile(context, userProfile)
alaAuthClient.isMultiProfile(context, userProfile)
)

result = true
Expand Down

0 comments on commit efde9b2

Please sign in to comment.