diff --git a/build.gradle b/build.gradle
index ebe5c5b76..691470875 100644
--- a/build.gradle
+++ b/build.gradle
@@ -154,7 +154,7 @@ dependencies {
if (!Boolean.valueOf(inplace)) {
implementation "org.grails.plugins:ala-map-plugin:3.0.1"
- implementation "org.grails.plugins:ecodata-client-plugin:6.1.3"
+ implementation "org.grails.plugins:ecodata-client-plugin:6.2"
}
testCompileOnly "org.grails:grails-test-mixins:3.3.0"
diff --git a/gradle.properties b/gradle.properties
index b16400354..f64e31ca3 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
-biocollectVersion=6.8-REFASSESS-SNAPSHOT
+biocollectVersion=6.8-LOGIN-SNAPSHOT
grailsVersion=5.1.9
grailsGradlePluginVersion=5.1.5
assetPipelineVersion=3.3.4
diff --git a/grails-app/assets/javascripts/document.js b/grails-app/assets/javascripts/document.js
index c861bf545..8c6bb2659 100644
--- a/grails-app/assets/javascripts/document.js
+++ b/grails-app/assets/javascripts/document.js
@@ -283,6 +283,7 @@ function attachViewModelToFileUpload(uploadUrl, documentViewModel, uiSelector, p
$(uiSelector).fileupload({
url:uploadUrl,
pasteZone: null,
+ dropZone: null,
formData:function(form) {
return [{name:'document', value:documentViewModel.toJSONString()}]
},
diff --git a/grails-app/assets/javascripts/i18n.js b/grails-app/assets/javascripts/i18n.js
new file mode 100644
index 000000000..d4fad5d2f
--- /dev/null
+++ b/grails-app/assets/javascripts/i18n.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 Atlas of Living Australia
+ * All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Created by Temi on 15/11/19.
+ */
+
+(function() {
+ var messages = {},
+ deffer = $.Deferred();
+ $.get({
+ url: fcConfig.i18nURL,
+ cache: true
+ }).done(function (data) {
+ messages = data;
+ deffer.resolve();
+ }).fail(function () {
+ deffer.reject();
+ });
+
+ $i18n = function(key, defaultValue) {
+ if (messages[key] !== undefined) {
+ return messages[key];
+ } else {
+ return defaultValue || key;
+ }
+ };
+
+ $i18nAsync = function(key, defaultValue, callback) {
+ if (callback) {
+ deffer.done(function () {
+ callback($i18n(key, defaultValue));
+ }).fail(function () {
+ callback($i18n(key, defaultValue));
+ })
+ }
+ }
+
+})();
diff --git a/grails-app/assets/javascripts/knockout-custom-bindings.js b/grails-app/assets/javascripts/knockout-custom-bindings.js
index 79cf95b83..05b91c8a7 100644
--- a/grails-app/assets/javascripts/knockout-custom-bindings.js
+++ b/grails-app/assets/javascripts/knockout-custom-bindings.js
@@ -281,6 +281,7 @@ ko.bindingHandlers.stagedImageUpload = {
$(element).fileupload({
url: config.url,
pasteZone: null,
+ dropZone: null,
autoUpload: true
}).on('fileuploadadd', function (e, data) {
complete(false);
@@ -703,11 +704,11 @@ ko.bindingHandlers.fileUploadNoImage = {
var defaults = {autoUpload: true};
var settings = {
- pasteZone: null
+ pasteZone: null,
+ dropZone: null
};
$.extend(settings, defaults, options());
- $(element).fileupload(settings
- ).on('fileuploadadd', function (e, data) {
+ $(element).fileupload(settings).on('fileuploadadd', function (e, data) {
window.incrementAsyncCounter && window.incrementAsyncCounter();
}).on('fileuploaddone', function (e, data) {
window.decreaseAsyncCounter && window.decreaseAsyncCounter();
@@ -1148,4 +1149,49 @@ ko.bindingHandlers.debug = {
console.log(element);
console.log(ko.toJS(valueAccessor()));
}
-};
\ No newline at end of file
+};
+
+
+/**
+ * This binding requires i18n.js to be loaded. It also requires fcConfig.i18nURL to be set.
+ * Params can be a string or an object. If string, it is treated as key and translated to text. Object parameter has the
+ * following properties:
+ * @contentType can be 'text' or 'html' (default is 'text')
+ * @key is the key to be translated
+ * @defaultValue is the default value to be used if the key is not found
+ *
+ * Usage examples:
+ *
+ *
+ *
+ */
+ko.bindingHandlers.i18n = {
+ init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
+ var value = valueAccessor();
+ value = ko.unwrap(value);
+ var contentType = value && value.contentType || 'text'
+
+ // $i18nAsync is required to be defined
+ if(typeof $i18nAsync === 'undefined')
+ return
+
+ if( typeof value === 'string') {
+ $i18nAsync(value, '',function(text) {
+ $(element).text(text);
+ });
+ }
+ else if (typeof value === 'object') {
+ $i18nAsync(value.key, value.defaultValue,function(text) {
+ switch (contentType) {
+ default:
+ case 'text':
+ $(element).text(text);
+ break;
+ case 'html':
+ $(element).html(text);
+ break;
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/grails-app/assets/javascripts/outputs.js b/grails-app/assets/javascripts/outputs.js
index 7c091cc87..7cefb6a54 100644
--- a/grails-app/assets/javascripts/outputs.js
+++ b/grails-app/assets/javascripts/outputs.js
@@ -152,6 +152,7 @@ ko.bindingHandlers.photoPointUpload = {
$(element).fileupload({
url:config.url,
pasteZone: null,
+ dropZone: null,
autoUpload:true
}).on('fileuploadadd', function(e, data) {
complete(false);
@@ -360,6 +361,7 @@ ko.bindingHandlers.fileUploadWithProgress = {
$(element).fileupload({
url: config.url,
pasteZone: null,
+ dropZone: null,
autoUpload: true
}).on('fileuploadadd', function (e, data) {
complete(false);
diff --git a/grails-app/conf/application.groovy b/grails-app/conf/application.groovy
index 296b787ad..401ad2b13 100644
--- a/grails-app/conf/application.groovy
+++ b/grails-app/conf/application.groovy
@@ -27,7 +27,7 @@ environments {
temp.dir = "/data/biocollect/temp"
// system level config
server.port = 8087
- serverURL = "http://devt.ala.org.au:8087"
+ serverURL = "http://localhost:8087"
biocollect.system.email.replyTo = "biocollect-dev@ala.org.au"
sender = "biocollect-dev@ala.org.au"
debugUI = true
@@ -36,11 +36,10 @@ environments {
}
test {
- spring.autoconfigure.exclude="au.org.ala.ws.security.AlaWsSecurityConfiguration"
debugUI = false
loggerLevel = "DEBUG"
server.port = "8087"
- grails.host = "http://devt.ala.org.au"
+ grails.host = "http://localhost"
serverName = "${grails.host}:${server.port}"
grails.serverURL = serverName
server.serverURL = serverName
@@ -51,8 +50,8 @@ environments {
grails.config.locations = []
security.oidc.discoveryUri = "http://localhost:${wiremock.port}/cas/oidc/.well-known"
security.oidc.allowUnsignedIdTokens = true
- def casBaseUrl = "http://devt.ala.org.au:${wiremock.port}"
-
+ def casBaseUrl = "http://localhost:${wiremock.port}"
+ ehcache.directory = './ehcache'
security.cas.appServerName=serverName
security.cas.contextPath=
security.cas.casServerName="${casBaseUrl}"
@@ -61,17 +60,17 @@ environments {
security.cas.loginUrl="${security.cas.casServerUrlPrefix}/login"
security.cas.casLoginUrl="${security.cas.casServerUrlPrefix}/login"
security.cas.logoutUrl="${security.cas.casServerUrlPrefix}/logout"
+ userDetails.api.url = "${casBaseUrl}/userdetails/userDetails/"
security.jwt.discoveryUri="${casBaseUrl}/cas/oidc/.well-known"
userDetails.url = "${casBaseUrl}/userdetails/userDetails/"
- userDetailsSingleUrl = "${userDetails.Url}getUserDetails"
- userDetailsUrl = "${userDetatails.url}getUserListFull"
+ userDetailsSingleUrl = "${userDetails.url}getUserDetails"
logging.dir = '.'
upload.images.path = '/tmp'
upload.images.url = grails.serverURL+'/image/'
- ecodata.baseUrl = 'http://devt.ala.org.au:8080/'
- ecodata.baseURL = 'http://devt.ala.org.au:8080'
- ecodata.service.url = 'http://devt.ala.org.au:8080/ws'
- pdfgen.baseURL = "http://devt.ala.org.au:${wiremock.port}/"
+ ecodata.baseUrl = 'http://localhost:8080/'
+ ecodata.baseURL = 'http://localhost:8080'
+ ecodata.service.url = 'http://localhost:8080/ws'
+ pdfgen.baseURL = "http://localhost:${wiremock.port}/"
api_key='testapikey'
grails.cache.config = {
diskStore {
diff --git a/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy b/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy
index 9062b447e..1bf80cd7a 100644
--- a/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy
+++ b/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy
@@ -14,6 +14,7 @@ class HomeController {
def settingService
def metadataService
def userService
+ CommonService commonService
@PreAuthorise(accessLevel = 'alaAdmin', redirectController = "admin")
@SSO
@@ -61,6 +62,13 @@ class HomeController {
def works() {
}
+ def i18n() {
+ if (request.isGet()) {
+ Map props = commonService.i18n(request.locale)
+ render props as JSON
+ }
+ }
+
/**
* The purpose of this method is to enable the display of the spatial object corresponding to a selected
* value from a geographic facet (e.g. to display the polygon representing NSW on the map if the user has
diff --git a/grails-app/services/au/org/ala/biocollect/merit/ActivityService.groovy b/grails-app/services/au/org/ala/biocollect/merit/ActivityService.groovy
index 7288aec23..ac29e5b1f 100644
--- a/grails-app/services/au/org/ala/biocollect/merit/ActivityService.groovy
+++ b/grails-app/services/au/org/ala/biocollect/merit/ActivityService.groovy
@@ -116,9 +116,9 @@ class ActivityService {
webService.doDelete(grailsApplication.config.ecodata.service.url + '/activity/' + id)
}
- def bulkDelete(List ids, boolean destory) {
+ def bulkDelete(List ids, boolean destroy = false) {
String url = grailsApplication.config.ecodata.service.url + '/activityBulkDelete'
- if(destory)
+ if(destroy)
url += '?destroy=true'
webService.doPost(url, [ids: ids])
}
diff --git a/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy b/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy
index 286fac098..1ba6ddf75 100644
--- a/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy
+++ b/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy
@@ -3,6 +3,7 @@ package au.org.ala.biocollect.merit
import grails.converters.JSON
import grails.web.mapping.LinkGenerator
import grails.web.servlet.mvc.GrailsParameterMap
+import org.springframework.context.MessageSource
import javax.servlet.http.HttpServletRequest
import javax.xml.bind.DatatypeConverter
@@ -13,6 +14,7 @@ class CommonService {
UserService userService
LinkGenerator grailsLinkGenerator
+ MessageSource messageSource
List ignores = ["action","controller"]
@@ -92,4 +94,7 @@ class CommonService {
queryParams
}
+ def i18n(Locale locale) {
+ messageSource.getMergedProperties(locale)?.properties
+ }
}
diff --git a/grails-app/services/au/org/ala/biocollect/merit/SettingService.groovy b/grails-app/services/au/org/ala/biocollect/merit/SettingService.groovy
index de7103f33..1612eb9c9 100644
--- a/grails-app/services/au/org/ala/biocollect/merit/SettingService.groovy
+++ b/grails-app/services/au/org/ala/biocollect/merit/SettingService.groovy
@@ -100,9 +100,10 @@ class SettingService {
}
def loadHubConfig(hub) {
-
+ def defaultHub = grailsApplication.config.getProperty('app.default.hub', String, 'default')
if (!hub) {
- hub = grailsApplication.config.app.default.hub?:'default'
+ hub = cookieService.getCookie(LAST_ACCESSED_HUB)
+ hub = hub ?: defaultHub
}
else {
// Hub value in multiple places like url path and in parameter causes Array to be passed instead of String.
@@ -131,7 +132,10 @@ class SettingService {
)
}
- cookieService.setCookie(LAST_ACCESSED_HUB, settings?.urlPath, -1 /* -1 means the cookie expires when the browser is closed */)
+ // Do not set cookie value to default hub since it overwrites genuine hub selection when calls are made with default hub.
+ // This usually happens when calls are made without hub parameter like downloading images.
+ if (settings?.urlPath != defaultHub)
+ cookieService.setCookie(LAST_ACCESSED_HUB, settings?.urlPath, -1 /* -1 means the cookie expires when the browser is closed */, '/')
GrailsWebRequest.lookup().params.hub = settings?.urlPath
SettingService.setHubConfig(settings)
}
diff --git a/grails-app/taglib/au/org/ala/biocollect/TemplateTagLib.groovy b/grails-app/taglib/au/org/ala/biocollect/TemplateTagLib.groovy
index d60a4f04f..3d8abeaf7 100644
--- a/grails-app/taglib/au/org/ala/biocollect/TemplateTagLib.groovy
+++ b/grails-app/taglib/au/org/ala/biocollect/TemplateTagLib.groovy
@@ -2,6 +2,7 @@ package au.org.ala.biocollect
import au.org.ala.biocollect.merit.SettingService
import au.org.ala.biocollect.merit.UserService
+import org.grails.web.servlet.mvc.GrailsWebRequest
import org.springframework.context.MessageSource
class TemplateTagLib {
@@ -134,25 +135,39 @@ class TemplateTagLib {
}
break;
case 'login':
+ // HubAwareLinkGenerator adds hub parameter to the link which causes subsequent URL parsing to return null in Pac4J filter.
+ // This causes the app to redirect to root page. And, BioCollect root page is redirected to Wordpress.
+ // Taking the user outside the application. This is a workaround to fix the issue. First, remove the
+ // hub parameter before link is generated and set it afterwards.
+ def hub = clearHubParameter()
+ def logoutReturnToUrl = getCurrentURL( attrs.hubConfig )
+ if (grailsApplication.config.getProperty("security.oidc.logoutAction",String, "CAS") == "cognito") {
+ // cannot use createLink since it adds hub query parameter and cognito will not consider it valid
+ logoutReturnToUrl = grailsApplication.config.getProperty("grails.serverURL") + grailsApplication.config.getProperty("logoutReturnToUrl",String, "/hub/index")
+ }
+
if (bs4) {
out << "";
} else {
out << "";
out << auth.loginLogout(
ignoreCookie: "true",
- logoutUrl: "${createLink(controller: 'logout', action: 'logout')}",
+// cannot use createLink since it adds hub query parameter and eventually creates malformed URL with two ? characters
+ logoutUrl: "/logout",
loginReturnToUrl: getCurrentURL( attrs.hubConfig ),
- logoutReturnToUrl: getCurrentURL( attrs.hubConfig )
+ logoutReturnToUrl: logoutReturnToUrl
)
out << "";
}
+ setHubParameter(hub)
break;
case 'newproject':
if (bs4) {
@@ -319,6 +334,21 @@ class TemplateTagLib {
}
}
+ String getCurrentURLFromRequest() {
+ String requestURL = request.getRequestURL().toString()
+ // Construct the complete URL
+ StringBuilder url = new StringBuilder()
+ url.append(requestURL)
+
+ String queryString = request.getQueryString()
+ // Include the query string if present
+ if (queryString != null) {
+ url.append("?").append(queryString)
+ }
+
+ url.toString()
+ }
+
private String getLinkUrl (Map link){
String url;
@@ -402,6 +432,23 @@ class TemplateTagLib {
}
private String getCurrentURL(Map hubConfig){
- g.createLink(absolute: true, uri: '/').toString()
+ getCurrentURLFromRequest()
+ }
+
+ private String clearHubParameter(){
+ def request = GrailsWebRequest.lookup()
+ def hub = request?.params?.hub
+ if(hub){
+ request.params.remove('hub')
+ }
+
+ hub
+ }
+
+ private void setHubParameter(String hub) {
+ def request = GrailsWebRequest.lookup()
+ if (hub && request.params) {
+ request.params.hub = hub
+ }
}
}
diff --git a/package-lock.json b/package-lock.json
index b15fcf222..3e47a17b2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "6.0",
"devDependencies": {
"@metahub/karma-jasmine-jquery": "^2.0.1",
- "chromedriver": "^123.0.1",
+ "chromedriver": "^123.0.3",
"jasmine-core": "^3.5.0",
"jasmine-jquery": "^2.0.0",
"jquery": "^3.4.1",
@@ -180,13 +180,20 @@
}
},
"node_modules/@babel/traverse/node_modules/debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
- "ms": "^2.1.1"
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
"node_modules/@babel/traverse/node_modules/ms": {
@@ -682,9 +689,9 @@
}
},
"node_modules/chromedriver": {
- "version": "123.0.1",
- "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.1.tgz",
- "integrity": "sha512-YQUIP/zdlzDIRCZNCv6rEVDSY4RAxo/tDL0OiGPPuai+z8unRNqJr/9V6XTBypVFyDheXNalKt9QxEqdMPuLAQ==",
+ "version": "123.0.3",
+ "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.3.tgz",
+ "integrity": "sha512-35IeTqDLcVR0htF9nD/Lh+g24EG088WHVKXBXiFyWq+2lelnoM0B3tKTBiUEjLng0GnELI4QyQPFK7i97Fz1fQ==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -1945,9 +1952,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -2005,13 +2012,20 @@
}
},
"node_modules/istanbul-lib-source-maps/node_modules/debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
- "ms": "^2.1.1"
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
"node_modules/istanbul-lib-source-maps/node_modules/ms": {
@@ -3059,9 +3073,9 @@
"dev": true
},
"node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@@ -3189,9 +3203,9 @@
"dev": true
},
"node_modules/socks": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz",
- "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"dev": true,
"dependencies": {
"ip-address": "^9.0.5",
@@ -3885,12 +3899,12 @@
},
"dependencies": {
"debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
- "ms": "^2.1.1"
+ "ms": "2.1.2"
}
},
"ms": {
@@ -4285,9 +4299,9 @@
}
},
"chromedriver": {
- "version": "123.0.1",
- "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.1.tgz",
- "integrity": "sha512-YQUIP/zdlzDIRCZNCv6rEVDSY4RAxo/tDL0OiGPPuai+z8unRNqJr/9V6XTBypVFyDheXNalKt9QxEqdMPuLAQ==",
+ "version": "123.0.3",
+ "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.3.tgz",
+ "integrity": "sha512-35IeTqDLcVR0htF9nD/Lh+g24EG088WHVKXBXiFyWq+2lelnoM0B3tKTBiUEjLng0GnELI4QyQPFK7i97Fz1fQ==",
"dev": true,
"requires": {
"@testim/chrome-version": "^1.1.4",
@@ -5274,9 +5288,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -5323,12 +5337,12 @@
},
"dependencies": {
"debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
- "ms": "^2.1.1"
+ "ms": "2.1.2"
}
},
"ms": {
@@ -6127,9 +6141,9 @@
"dev": true
},
"semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"setprototypeof": {
@@ -6229,9 +6243,9 @@
}
},
"socks": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz",
- "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"dev": true,
"requires": {
"ip-address": "^9.0.5",
diff --git a/package.json b/package.json
index eaa797d6b..1b726a969 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
},
"devDependencies": {
"@metahub/karma-jasmine-jquery": "^2.0.1",
- "chromedriver": "^123.0.1",
+ "chromedriver": "^123.0.3",
"jasmine-core": "^3.5.0",
"jasmine-jquery": "^2.0.0",
"jquery": "^3.4.1",
diff --git a/src/integration-test/groovy/au/org/ala/biocollect/AddBioActivitySpec.groovy b/src/integration-test/groovy/au/org/ala/biocollect/AddBioActivitySpec.groovy
index 7c7614ba6..0d480e23c 100644
--- a/src/integration-test/groovy/au/org/ala/biocollect/AddBioActivitySpec.groovy
+++ b/src/integration-test/groovy/au/org/ala/biocollect/AddBioActivitySpec.groovy
@@ -12,7 +12,7 @@ class AddBioActivitySpec extends StubbedCasSpec {
}
def cleanupSpec() {
- logout(browser)
+ logout(browser, ViewBioActivityPage)
}
def projectId = "project_1"
diff --git a/src/integration-test/groovy/au/org/ala/biocollect/BiocollectFunctionalTest.groovy b/src/integration-test/groovy/au/org/ala/biocollect/BiocollectFunctionalTest.groovy
index ee6ba23cf..91035f434 100644
--- a/src/integration-test/groovy/au/org/ala/biocollect/BiocollectFunctionalTest.groovy
+++ b/src/integration-test/groovy/au/org/ala/biocollect/BiocollectFunctionalTest.groovy
@@ -134,7 +134,7 @@ class BiocollectFunctionalTest extends GebReportingSpec {
def logoutViaUrl(browser) {
String serverUrl = (testConfig.baseUrl instanceof String) ? testConfig.baseUrl : testConfig.grails.serverURL
- String logoutUrl = "${serverUrl}/logout/logout?appUrl=${serverUrl}"
+ String logoutUrl = "${serverUrl}/logout?appUrl=${serverUrl}"
browser.go logoutUrl
}
diff --git a/src/integration-test/groovy/au/org/ala/biocollect/StubbedCasSpec.groovy b/src/integration-test/groovy/au/org/ala/biocollect/StubbedCasSpec.groovy
index d5eee7679..caca97341 100644
--- a/src/integration-test/groovy/au/org/ala/biocollect/StubbedCasSpec.groovy
+++ b/src/integration-test/groovy/au/org/ala/biocollect/StubbedCasSpec.groovy
@@ -2,21 +2,26 @@ package au.org.ala.biocollect
import com.github.tomakehurst.wiremock.WireMockServer
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer
+import com.nimbusds.jose.jwk.RSAKey
import geb.Browser
import grails.converters.JSON
import org.grails.web.converters.marshaller.json.CollectionMarshaller
import org.grails.web.converters.marshaller.json.MapMarshaller
import org.openqa.selenium.StaleElementReferenceException
+import org.openqa.selenium.WebDriverException
+import org.pac4j.jwt.config.signature.RSASignatureConfiguration
import org.pac4j.jwt.profile.JwtGenerator
-import spock.lang.Shared
import wiremock.com.github.jknack.handlebars.EscapingStrategy
import wiremock.com.github.jknack.handlebars.Handlebars
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import wiremock.com.google.common.collect.ImmutableMap
+import java.security.KeyPair
+
import static com.github.tomakehurst.wiremock.client.WireMock.*
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options
+
//import com.github.tomakehurst.wiremock.WireMockServer
/**
@@ -28,33 +33,64 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
static String GRANT_MANAGER_USER_ID = '1001'
static String MERIT_ADMIN_USER_ID = '1002'
static String ALA_ADMIN_USER_ID = '2000'
+ static KeyPair pair
+ static RSAKey signingKey
+ static {
+ // KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA")
+ // generator.initialize(2048)
+ // pair = generator.generateKeyPair()
+ //
+ // signingKey = new RSAKey.Builder(pair.getPublic()).privateKey(pair.getPrivate()).build()
+ // RSAKey publicKey = new RSAKey.Builder(pair.getPublic()).build()
+ // println signingKey.toJSONObject() - this is hardcoded below and is used to sign tokens
+ // println publicKey.toJSONObject() - this goes into wiremock as the response to the jwks request
+
+ // It would be better to generate this at runtime, but the stub needs to be in wirework during bean initialisation of MERIT
+ // So we've generated a random key as above and coded it here and into the wiremock stub
+ Map key = ["p":"ybsLU3Xf05Nkmfthec3Gf5SCR1cMG4gHYTJh9dP575RavQO63oxS9G-srVmNTmCYsoi-KJs9RODO8Ive701DrpSBkeM7cYZ5_7J3Zt7kTtIPCavwJsb0yhyJQGcm6v7iuF8GIRukeKLT57LwjhSPPqZgdOu9elsc3T7-D9jPPBE",
+ "kty":"RSA",
+ "q":"rA9mDEolsAG9br7CJlgPIaNsAdpPmqwGTnaHZgJCeN3XwKLlTkLiBlH66OdvakvoFHuvoiaUXFx2xd0G-WrBdePnqZcAb0SdLMp0RxDCRyC4HwJSE9YwieOpIO8EvgzYZKL7liUKR0fz3HAciV9oW3lA6bnh1doSVadw18LMKZk",
+ "d":"GDawqqYZsTqZpR3WRyK1YoSI0qO4RS61jvW-l72SbpILYHl9M0cZewef95OrT9yl4-7SurBV15j7wkqLvLxmQNxpIs-yXRK5hpmvxa07SiXZOtwW7EvG_PMx9tyQ8LiyM8MnTr-qknh_Rtbjr9bH0mrMeUCQfVj5VSSF8SNHEVPGy_QxQoswIhRgzcq9tOaGP1W-FoVCaQjAxJG4boAselX_bvYe3IVuDwE_ZV8KPCQcZISEqrY8B8-b8AdTgecORODQB5lChElqRBeKUeoOtVMvD8rlwUgjV9ir_QK25Vq8rLcEkdPrRhV0EKKnr1eBir1WSpdLjzIUhAsF5HPUAQ",
+ "e":"AQAB", "qi":"kuYhMgrJR1fTuX0IJar-SjWhrn3EV96bfaObAkxMZDHes-tthLxcZ58PpKKbsMSK8kncT41JMb0Irb9HC12B6aSDy3Kzsns-gzcD38m9YcdOk80kyjCqLIceU2tmMIeIxSF54wGwVO_p4p94xeANf4si450ssqdPM_q1n1SRu88",
+ "dp":"Gx8Nj8P6OqzHSrh0S3bx5_ckaMj4NL9eFqA6cV11bdNpO55DwmXlRT26Xnf6un3cKayevEDaxObgi5CSgWPG5LLMlLuTI1ksD8eDrA3tbfdp1CgMmnoHMSETBtiXb-Kiwpzr6wmXXCywBqeVFdUHySl_MFj9WXTkdY5hg-nnOrE",
+ "dq":"DwhxZBV-YXhlcq2cDPmYqNm8cBUA64SoMGbOwazk3eaUGTKiUkopsV-sSnkeFO1444FDASnZwJAbmIINP_GB4aj97qVQ1mfqS6WMr0DZmJlVPPBY9365UvLfLg90HJ7GsVREIwQtd7jjp5jsBVyeo49eio1BHAwnmfA9Pby5VdE",
+ "n":"h5XN-_LL1yXb8oPWHOTNMby0Y6olpByVCNJGo1mjhk9PUoX8bfu6wNr4G7oR7O0NfIQVNLykqE7Q04RrP7JfexI97UuH5B0xBjHVo-S5SxeyUrVSQBpRu6EisQzxxF3a038a0GHYJpA5YUAZWD7Pux0yqJ5ly1y2Sn7uGb_JJ_bJ86EVWs3AxE1RZHmeY975A1kk470ylDAyfQuW_GU-gUzG5vdE1wAEIKe6GFtg5ulA_n_XVsrz9qio7ZtEyWZDAOCtk0jfg8iTJf5eLP2Q3D8ePy_6IvYvFDuQLmvKHn1jg5MnnDWZHV3GBRnfU8CtPu2ChFKhXedcrhQhhAWfKQ"
+ ]
+
+ signingKey = RSAKey.parse(key)
+ pair = signingKey.toKeyPair()
- @Shared WireMockServer wireMockServer
+ }
+
+ // @Shared WireMockServer wireMockServer
def setupSpec() {
+ JSON.registerObjectMarshaller(new MapMarshaller())
+ JSON.registerObjectMarshaller(new CollectionMarshaller())
if (testConfig.wiremock.embedded){
+ startWireMock()
+ }
+
+ // Configure the client
+ configureFor("localhost", testConfig.wiremock.port)
+ }
- Handlebars handlebars = new Handlebars()
- handlebars.escapingStrategy = EscapingStrategy.NOOP
+ private void startWireMock() {
+ Handlebars handlebars = new Handlebars()
+ handlebars.escapingStrategy = EscapingStrategy.NOOP
- // This is done so we can use a custom handlebars with a NOOP escaping strategy - the default escapes HTML
- // which breaks the redirect URL returned by the PDF generation stub.
- Helper noop = new Helper() {
- Object apply(Object context, Options options) throws IOException {
- return context[0]
- }
+ // This is done so we can use a custom handlebars with a NOOP escaping strategy - the default escapes HTML
+ // which breaks the redirect URL returned by the PDF generation stub.
+ Helper noop = new Helper() {
+ Object apply(Object context, Options options) throws IOException {
+ return context[0]
}
- wireMockServer = new WireMockServer(options()
- .port(testConfig.wiremock.port)
- .usingFilesUnderDirectory(getMappingsPath())
- .extensions(new ResponseTemplateTransformer(false, handlebars, ImmutableMap.of("noop", noop), null, null)))
-
- wireMockServer.start()
}
+ wireMockServer = new WireMockServer(options()
+ .port(testConfig.wiremock.port)
+ .usingFilesUnderDirectory(getMappingsPath())
+ .extensions(new ResponseTemplateTransformer(false, handlebars, ImmutableMap.of("noop", noop), null, null)))
- JSON.registerObjectMarshaller(new MapMarshaller())
- JSON.registerObjectMarshaller(new CollectionMarshaller())
- // Configure the client
- configureFor("localhost", testConfig.wiremock.port)
+ wireMockServer.start()
}
def cleanupSpec() {
@@ -113,6 +149,12 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
}
catch (StaleElementReferenceException e) { // Do nothing, backdrop was already detached
}
+ catch (NullPointerException e) {
+ // Do nothing, backdrop was already detached and destroyed before we selected it
+ }
+ catch (WebDriverException e) {
+ // We are now seeing WebDriverException instead of StateElementReferenceException in some cases
+ }
}
private String getMappingsPath() {
@@ -133,7 +175,7 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
}
/** Convenience method to stub the login of a user with the CAS ROLE_ALA_ADMIN role */
def loginAsAlaAdmin(Browser browser) {
- login([userId:ALA_ADMIN_USER_ID, role:"ROLE_ADMIN", email: 'ala_admin@nowhere.com', firstName:"ALA", lastName:"Administrator"], browser)
+ login([userId:ALA_ADMIN_USER_ID, role:"ROLE_ADMIN", userName: 'ala_admin@nowhere.com', email: 'ala_admin@nowhere.com', firstName:"ALA", lastName:"Administrator"], browser)
}
/** Convenience method to stub the login of a user no special roles */
def loginAsUser(String userId, Browser browser) {
@@ -143,6 +185,11 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
login([userId:userId, email: "user${userId}@nowhere.com", firstName:"MERIT", lastName:"User ${userId}"], browser)
}
+ String tokenForUser(String userId) {
+ Map userDetails = [userId:userId, email: "user${userId}@nowhere.com", firstName:"MERIT", lastName:"User ${userId}"]
+ setupOidcAuthForUser(userDetails)
+ }
+
private String loggedInUser = null
def login(Map userDetails, Browser browser) {
@@ -154,7 +201,17 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
}
def oidcLogin(Map userDetails, Browser browser) {
+ setupOidcAuthForUser(userDetails)
+ browser.go "${browser.getConfig().baseUrl}login"
+ }
+ /**
+ * Sets up stubs with wiremock to authenticate a user via OIDC. Also returns an idToken which can be used
+ * if an interactive login is not required.
+ * @param userDetails the details of the user to setup
+ * @return an idToken for the user.
+ */
+ String setupOidcAuthForUser(Map userDetails) {
// The test config isn't a normal grails config object (probably need to to into why) so getProperty doesn't work.
String clientId = getTestConfig().security.oidc.clientId
List roles = ["ROLE_USER"]
@@ -182,16 +239,17 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
exp:com.nimbusds.jwt.util.DateUtils.toSecondsSinceEpoch(new Date().plus(365)),
iat:com.nimbusds.jwt.util.DateUtils.toSecondsSinceEpoch(new Date()),
jti:"id",
- email:userDetails.email
+ email:userDetails.email,
+ scope : "openid profile ala roles email"
]
- String idToken = new JwtGenerator(null).generate(idTokenClaims)
+ String idToken = new JwtGenerator(new RSASignatureConfiguration(pair)).generate(idTokenClaims)
Map token = [:]
token.access_token = idToken
token.id_token = idToken
token.refresh_token = null
token.token_type = "bearer"
token.expires_in = 86400
- token.scope = "user_defined email openid profile roles"
+ token.scope = "openid profile ala roles email"
stubFor(post(urlPathEqualTo("/cas/oidc/oidcAccessToken"))
.willReturn(aResponse()
@@ -203,11 +261,12 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
Map profile = [
- sub:userDetails.userId,
- name:userDetails.firstName+" "+userDetails.lastName,
- given_name:userDetails.firstName,
- family_name:userDetails.lastName,
- email:userDetails.email
+ userid : userDetails.userId,
+ sub : userDetails.userId,
+ name : userDetails.firstName + " " + userDetails.lastName,
+ given_name : userDetails.firstName,
+ family_name: userDetails.lastName,
+ email : userDetails.email
]
stubFor(get(urlPathEqualTo("/cas/oidc/oidcProfile"))
@@ -216,8 +275,7 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
.withHeader("Content-Type", "application/json")
.withBody((profile as JSON).toString())
))
-
- browser.go "${getConfig().baseUrl}login"
+ idToken
}
/** Creates a wiremock configuration to stub a user login request and return the supplied user and role information */
@@ -272,14 +330,14 @@ class StubbedCasSpec extends BiocollectFunctionalTest {
.willReturn(aResponse()
.withStatus(302)
- .withHeader("Location", "{{{request.requestLine.query.service}}}?ticket=aticket")
+ .withHeader("Location", "{{request.requestLine.query.service}}?ticket=aticket")
.withHeader("Set-Cookie", "ALA-Auth=\"${email}\"; Domain=ala.org.au; Path=/; HttpOnly")
.withTransformers("response-template")))
stubFor(get(urlMatching("/cas/login\\?service=.*\\?.*"))
.willReturn(aResponse()
.withStatus(302)
- .withHeader("location", "{{{request.requestLine.query.service}}}&ticket=aticket")
+ .withHeader("location", "{{request.requestLine.query.service}}&ticket=aticket")
.withHeader("Set-Cookie", "ALA-Auth=\"${email}\"; Domain=ala.org.au; Path=/; HttpOnly")
.withTransformers("response-template")))
diff --git a/src/integration-test/resources/GebConfig.groovy b/src/integration-test/resources/GebConfig.groovy
index f17c4eff0..11d470fe7 100644
--- a/src/integration-test/resources/GebConfig.groovy
+++ b/src/integration-test/resources/GebConfig.groovy
@@ -14,7 +14,7 @@ if (!System.getProperty("webdriver.chrome.driver")) {
System.setProperty("webdriver.chrome.driver", "node_modules/chromedriver/bin/chromedriver")
}
driver = { new ChromeDriver() }
-baseUrl = 'http://devt.ala.org.au:8087/'
+baseUrl = 'http://localhost:8087/'
atCheckWaiting = true
waiting {
timeout = 20
diff --git a/src/integration-test/resources/wiremock/mappings/jwkSource.json b/src/integration-test/resources/wiremock/mappings/jwkSource.json
new file mode 100644
index 000000000..77c820a5a
--- /dev/null
+++ b/src/integration-test/resources/wiremock/mappings/jwkSource.json
@@ -0,0 +1,25 @@
+{
+ "request": {
+ "urlPath": "/cas/oidc/jwks",
+ "method": "GET"
+ },
+ "response" : {
+ "status": 200,
+ "headers": {
+ "content-Type": "application/json"
+ },
+ "jsonBody": {
+ "keys": [
+ {
+ "kty":"RSA",
+ "e":"AQAB",
+ "use":"sig",
+ "alg": "RS256",
+ "kid":"localhost:8018",
+ "n": "h5XN-_LL1yXb8oPWHOTNMby0Y6olpByVCNJGo1mjhk9PUoX8bfu6wNr4G7oR7O0NfIQVNLykqE7Q04RrP7JfexI97UuH5B0xBjHVo-S5SxeyUrVSQBpRu6EisQzxxF3a038a0GHYJpA5YUAZWD7Pux0yqJ5ly1y2Sn7uGb_JJ_bJ86EVWs3AxE1RZHmeY975A1kk470ylDAyfQuW_GU-gUzG5vdE1wAEIKe6GFtg5ulA_n_XVsrz9qio7ZtEyWZDAOCtk0jfg8iTJf5eLP2Q3D8ePy_6IvYvFDuQLmvKHn1jg5MnnDWZHV3GBRnfU8CtPu2ChFKhXedcrhQhhAWfKQ"
+ }
+ ]
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/integration-test/resources/wiremock/mappings/oidcDiscovery.json b/src/integration-test/resources/wiremock/mappings/oidcDiscovery.json
index b5f27fb99..5b27ec350 100644
--- a/src/integration-test/resources/wiremock/mappings/oidcDiscovery.json
+++ b/src/integration-test/resources/wiremock/mappings/oidcDiscovery.json
@@ -64,7 +64,7 @@
"refresh_token"
],
"id_token_signing_alg_values_supported": [
- "none"
+ "RS256", "none"
],
"id_token_encryption_alg_values_supported": [
"none"
@@ -73,7 +73,7 @@
"none"
],
"userinfo_signing_alg_values_supported": [
- "none"
+ "RS256", "none"
],
"userinfo_encryption_alg_values_supported": [
"none"
@@ -82,7 +82,7 @@
"none"
],
"request_object_signing_alg_values_supported": [
- "none"
+ "RS256", "none"
],
"request_object_encryption_alg_values_supported": [
"none"
diff --git a/src/integration-test/resources/wiremock/mappings/oidcLogout.json b/src/integration-test/resources/wiremock/mappings/oidcLogout.json
new file mode 100644
index 000000000..f5d98af7a
--- /dev/null
+++ b/src/integration-test/resources/wiremock/mappings/oidcLogout.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "urlPath": "/cas/oidc/oidcLogout",
+ "method": "GET"
+ },
+ "response": {
+ "status": 302,
+ "headers": {
+ "location": "{{{request.requestLine.query.post_logout_redirect_uri}}}"
+ },
+ "transformers": [
+ "response-template"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/integration-test/resources/wiremock/mappings/userdetailsFromIDslookup.json b/src/integration-test/resources/wiremock/mappings/userdetailsFromIDslookup.json
index bc8773ca1..63ab4c129 100644
--- a/src/integration-test/resources/wiremock/mappings/userdetailsFromIDslookup.json
+++ b/src/integration-test/resources/wiremock/mappings/userdetailsFromIDslookup.json
@@ -14,21 +14,25 @@
"users": {
"1": {
"userName":"user1@user.com",
+ "email":"user1@user.com",
"firstName":"test1",
"lastName": "user1"
},
"10": {
"userName": "user10@user.com",
+ "email": "user10@user.com",
"firstName":"test10",
"lastName": "user10"
},
"30": {
"userName":"user30@user.com",
+ "email":"user30@user.com",
"firstName":"test30",
"lastName": "user30"
},
"1000": {
"userName":"user1000@user.com",
+ "email":"user1000@user.com",
"firstName":"test1000",
"lastName": "user1000"
},
@@ -39,11 +43,13 @@
},
"1002": {
"userName":"user1002@user.com",
+ "email":"user1002@user.com",
"firstName":"test1002",
"lastName": "user1002"
},
"2": {
"userName":"user2@user.com",
+ "email":"user2@user.com",
"firstName":"test2",
"lastName": "user2"
}
diff --git a/src/integration-test/resources/wiremock/mappings/userdetailslookup.json b/src/integration-test/resources/wiremock/mappings/userdetailslookup.json
index 71a5cda45..d0bc9790e 100644
--- a/src/integration-test/resources/wiremock/mappings/userdetailslookup.json
+++ b/src/integration-test/resources/wiremock/mappings/userdetailslookup.json
@@ -9,6 +9,12 @@
"headers": {
"Content-Type": "application/json"
},
- "body": "{\"userName\":\"user.{{request.query.userName}}@nowhere.com.au\", \"userId\":\"{{request.query.userName}}\"}"
+ "jsonBody": {
+ "userName":"user.{{request.query.userName}}@nowhere.com.au",
+ "email":"user.{{request.query.userName}}@nowhere.com.au",
+ "userId":"{{request.query.userName}}",
+ "firstName": "First {{request.query.userName}}",
+ "lastName": "Last {{request.query.userName}}"
+ }
}
}