Project

General

Profile

Actions

Task #3425

closed

Updating a user fails in Moodle 4.1

Added by Alena Peterová 9 months ago. Updated 8 months ago.

Status:
Closed
Priority:
Normal
Assignee:
Alena Peterová
Target version:
Start date:
08/11/2023
Due date:
% Done:

100%

Estimated time:
Owner:

Description

After upgrading Moodle to version 4.1 from 3.8, updating the user or the user's password fails with the exception below.
The reason is that newer Moodle API returns a different response (at least) for the function core_user_update_users.
Originally, a response for success was:

null

Now it is
{"warnings":[]}

The exact body of the response is checked in the result of the UpdateUser method because even unsuccessful operations end with HTTP 200, so the body must be checked in all cases.

Improve the connector so that it is compatible also with newer API responses, and also improve logging of the response in case of an exception.


java.lang.IllegalArgumentException: can't parse argument number: "warnings":[]
    at java.text.MessageFormat.makeFormat(MessageFormat.java:1429)
    at java.text.MessageFormat.applyPattern(MessageFormat.java:479)
    at java.text.MessageFormat.<init>(MessageFormat.java:362)
    at java.text.MessageFormat.format(MessageFormat.java:840)
    at org.identityconnectors.common.logging.Log.log(Log.java:208)
    at org.identityconnectors.common.logging.Log.error(Log.java:286)
    at eu.bcvsolutions.idm.connector.moodle.communication.Connection.handleError(Connection.java:82)
    at eu.bcvsolutions.idm.connector.moodle.operation.UpdateUser.updateUser(UpdateUser.java:80)
    at eu.bcvsolutions.idm.connector.moodle.MoodleConnector.update(MoodleConnector.java:114)
    at org.identityconnectors.framework.impl.api.local.operations.UpdateImpl.update(UpdateImpl.java:101)
    at sun.reflect.GeneratedMethodAccessor2553.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.identityconnectors.framework.impl.api.local.operations.ConnectorAPIOperationRunnerProxy.invoke(ConnectorAPIOperationRunnerProxy.java:98)
    at com.sun.proxy.$Proxy544.update(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor2553.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.identityconnectors.framework.impl.api.local.operations.ThreadClassLoaderManagerProxy.invoke(ThreadClassLoaderManagerProxy.java:96)
    at com.sun.proxy.$Proxy544.update(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor2553.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.identityconnectors.framework.impl.api.DelegatingTimeoutProxy.invoke(DelegatingTimeoutProxy.java:99)
    at com.sun.proxy.$Proxy544.update(Unknown Source)
    at org.identityconnectors.framework.impl.api.AbstractConnectorFacade.update(AbstractConnectorFacade.java:190)
    at eu.bcvsolutions.idm.ic.connid.service.impl.ConnIdIcConnectorService.updateObject(ConnIdIcConnectorService.java:119)
    at eu.bcvsolutions.idm.ic.service.impl.DefaultIcConnectorFacade.updateObject(DefaultIcConnectorFacade.java:64)
    at eu.bcvsolutions.idm.acc.event.processor.provisioning.ProvisioningUpdateProcessor.processInternal(ProvisioningUpdateProcessor.java:63)
    at eu.bcvsolutions.idm.acc.event.processor.provisioning.AbstractProvisioningProcessor.process(AbstractProvisioningProcessor.java:146)
    at eu.bcvsolutions.idm.core.api.event.AbstractEntityEventProcessor.onApplicationEvent(AbstractEntityEventProcessor.java:239)
    at eu.bcvsolutions.idm.core.api.event.AbstractEntityEventProcessor$$FastClassBySpringCGLIB$$df69624d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at eu.bcvsolutions.idm.acc.event.processor.provisioning.ProvisioningUpdateProcessor$$EnhancerBySpringCGLIB$$af7192dd.onApplicationEvent(<generated>)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:372)
    at eu.bcvsolutions.idm.core.model.service.impl.DefaultEntityEventManager.process(DefaultEntityEventManager.java:251)
    at eu.bcvsolutions.idm.core.model.service.impl.DefaultEntityEventManager.process(DefaultEntityEventManager.java:178)
    at eu.bcvsolutions.idm.core.model.service.impl.DefaultEntityEventManager$$FastClassBySpringCGLIB$$1694e58f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at eu.bcvsolutions.idm.core.model.service.impl.DefaultEntityEventManager$$EnhancerBySpringCGLIB$$7b11e416.process(<generated>)
    at eu.bcvsolutions.idm.acc.service.impl.DefaultProvisioningExecutor$1.call(DefaultProvisioningExecutor.java:181)
    at eu.bcvsolutions.idm.acc.service.impl.DefaultProvisioningExecutor$1.call(DefaultProvisioningExecutor.java:177)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at eu.bcvsolutions.idm.core.config.DelegatingTransactionContextRunnable.run(DelegatingTransactionContextRunnable.java:39)
    at org.springframework.security.concurrent.DelegatingSecurityContextRunnable.run(DelegatingSecurityContextRunnable.java:84)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NumberFormatException: For input string: ""warnings":[]" 
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:569)
    at java.lang.Integer.parseInt(Integer.java:615)
    at java.text.MessageFormat.makeFormat(MessageFormat.java:1427)
    ... 60 more
Actions #1

Updated by Alena Peterová 9 months ago

cURL examples for testing:

curl -k -X POST 'https://MOODLEADDRESS/webservice/rest/server.php?wstoken=.....&wsfunction=core_user_update_users&moodlewsrestformat=json'  --data-urlencode "users[0][id]=81"  --data-urlencode "users[0][password]=......" 

curl -k -X POST 'https://MOODLEADDRESS/webservice/rest/server.php?wstoken=......&wsfunction=core_user_update_users&moodlewsrestformat=json'  --data-urlencode "users[0][id]=81"  --data-urlencode "users[0][department]=testzmena" 

Example unsuccessful response:

curl -i -k -X POST 'https://MOODLEADDRESS/webservice/rest/server.php?wstoken=.....&wsfunction=core_user_update_users&moodlewsrestformat=json'  --data-urlencode "users[0][id]=1243"  --data-urlencode "users[0][password]=DDD" 
HTTP/1.1 200 OK
Date: Fri, 11 Aug 2023 13:27:50 GMT
Server: Apache/2.4.52 (Debian)
Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Accept-Ranges: none
Access-Control-Allow-Origin: *
Content-Length: 759
Content-Type: application/json

{"exception":"invalid_response_exception","errorcode":"invalidresponse","message":"Byla zji\u0161t\u011bna nespr\u00e1vn\u00e1 hodnota parametru","debuginfo":"warnings => Byla zji\u0161t\u011bna nespr\u00e1vn\u00e1 hodnota parametru: warningcode => Byla zji\u0161t\u011bna nespr\u00e1vn\u00e1 hodnota parametru: Invalid external api response: the value is \"<div>Minim\u00e1ln\u00ed po\u010det znak\u016f v heslech: 8<\/div><div>Minim\u00e1ln\u00ed po\u010det \u010d\u00edslic v heslech: 1<\/div><div>Minim\u00e1ln\u00ed po\u010det mal\u00fdch p\u00edsmen v heslech: 1<\/div><div>Hesla mus\u00ed m\u00edt nejm\u00e9n\u011b 1 speci\u00e1ln\u00edch znak\u016f jako jsou *, -, nebo #.<\/div>\" of PHP type \"string\", the server was expecting \"alphanum\" type"}

For version 3.8, the response was:

{"exception":"moodle_exception","errorcode":"<div>Passwords must be at least 8 characters long.<\/div><div>Passwords must have at least 1 digit(s).<\/div><div>Passwords must have at least 1 lower case letter(s).<\/div><div>Passwords must have at least 1 non-alphanumeric character(s) such as as *, -, or #.<\/div>","message":"error\/<div>Passwords must be at least 8 characters long.<\/div><div>Passwords must have at least 1 digit(s).<\/div><div>Passwords must have at least 1 lower case letter(s).<\/div><div>Passwords must have at least 1 non-alphanumeric character(s) such as as *, -, or #.<\/div>"}

Actions #2

Updated by Alena Peterová 8 months ago

  • Status changed from New to In Progress
  • Assignee set to Alena Peterová
Actions #3

Updated by Alena Peterová 8 months ago

  • % Done changed from 0 to 70

Changed in commit https://github.com/bcvsolutions/moodle-connector/commit/fd02c4bd9e9138483d4476422d843ef420e1c792 in apeterova/3425-upgrade-moodle-version.
Now, we distinguish error response by checking for the String "errorcode" in the response body. This should be universal for both versions.

Actions #4

Updated by Alena Peterová 8 months ago

  • Status changed from In Progress to Needs feedback
  • % Done changed from 70 to 90

Tested in a testing environment on version 4.1, all CRUD operations work correctly.

Error responses also work well, e.g. when we send incorrect value for the "timezone" attribute, the error in the provisioning is:

org.identityconnectors.framework.common.exceptions.ConnectorException: Operation update user failed, error code: invalidparameter,exception: invalid_parameter_exception, message: Byla zjištěna nesprávná hodnota parametru, debug: users => Byla zjištěna nesprávná hodnota parametru: timezone => Byla zjištěna nesprávná hodnota parametru: Invalid external api parameter: the value is "spatna data Europe/Prague", the server was expecting "timezone" type

Feedback remains.

Actions #6

Updated by Radek Erben 8 months ago

LGTM Alena!

Actions #7

Updated by Alena Peterová 8 months ago

  • Status changed from Needs feedback to Closed
  • Target version set to 1.0.2
  • % Done changed from 90 to 100

Merged and released as version 1.0.2.

Actions

Also available in: Atom PDF