From a5865fa6064110dacaf411d08923849d972cc52c Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Mon, 28 Sep 2020 13:07:37 +0200 Subject: [PATCH 1/7] Set owner in REST tasks Tasks created for execution of REST calls did not have ownerRef. This is now fixed. Resolves MID-6511. --- .../rest/impl/AbstractRestController.java | 47 ++- .../rest/impl/ClusterRestController.java | 20 +- .../impl/ExtensionSchemaRestController.java | 4 +- .../rest/impl/ModelRestController.java | 312 +++++++++--------- 4 files changed, 198 insertions(+), 185 deletions(-) diff --git a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java index 93040b5c469..c08dd27b601 100644 --- a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java +++ b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java @@ -68,9 +68,19 @@ protected Task initRequest() { // No need to audit login. it was already audited during authentication Task task = taskManager.createTaskInstance(opNamePrefix + "restService"); task.setChannel(SchemaConstants.CHANNEL_REST_URI); + PrismObject principalObject = getPrincipalObject(); + if (principalObject != null) { + task.setOwner(principalObject); + } return task; } + private PrismObject getPrincipalObject() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Object principal = authentication.getPrincipal(); + return principal instanceof MidPointPrincipal ? ((MidPointPrincipal) principal).getFocus().asPrismObject() : null; + } + protected OperationResult createSubresult(Task task, String operation) { return task.getResult().createSubresult(opNamePrefix + operation); } @@ -174,36 +184,29 @@ protected ResponseEntity createErrorResponseBuilder( return status(status).body(resultBean); } - protected void finishRequest() { - auditEvent(); - SecurityContextHolder.getContext().setAuthentication(null); - } - - private void auditEvent() { - String channel = SchemaConstants.CHANNEL_REST_URI; - SystemConfigurationType system = null; + protected void finishRequest(Task task, OperationResult result) { try { - system = systemObjectCache.getSystemConfiguration(new OperationResult("LOAD SYSTEM CONFIGURATION")).asObjectable(); - } catch (SchemaException e) { - logger.error("Couldn't get system configuration from cache", e); + auditLogout(task, result); + } finally { + SecurityContextHolder.getContext().setAuthentication(null); } - if (!SecurityUtil.isAuditedLoginAndLogout(system, channel)) { + } + + private void auditLogout(Task task, OperationResult result) { + if (isAuditingSkipped(result)) { return; } + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Object principal = authentication.getPrincipal(); String name = null; if (principal instanceof MidPointPrincipal) { name = ((MidPointPrincipal) principal).getUsername(); } else if (principal != null) { - return; + return; // TODO Why exit if principal non-null and continue if principal is null? } PrismObject user = principal != null ? ((MidPointPrincipal) principal).getFocus().asPrismObject() : null; - Task task = taskManager.createTaskInstance(); - task.setOwner(user); - task.setChannel(channel); - AuditEventRecord record = new AuditEventRecord(AuditEventType.TERMINATE_SESSION, AuditEventStage.REQUEST); record.setInitiator(user, prismContext); record.setParameter(name); @@ -218,6 +221,16 @@ private void auditEvent() { auditService.audit(record, task); } + private boolean isAuditingSkipped(OperationResult result) { + try { + SystemConfigurationType systemConfiguration = systemObjectCache.getSystemConfiguration(result).asObjectable(); + return !SecurityUtil.isAuditedLoginAndLogout(systemConfiguration, SchemaConstants.CHANNEL_REST_URI); + } catch (SchemaException e) { + logger.error("Couldn't get system configuration from cache, skipping REST logout auditing", e); + return true; + } + } + private final String[] requestMappingPaths = getClass().getAnnotation(RequestMapping.class).value(); diff --git a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ClusterRestController.java b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ClusterRestController.java index fd5cadf7ecd..00689697118 100644 --- a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ClusterRestController.java +++ b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ClusterRestController.java @@ -113,7 +113,7 @@ public ResponseEntity executeClusterCacheInvalidationEvent( } catch (Throwable t) { response = handleException(result, t); } - finishRequest(); + finishRequest(task, result); return response; } @@ -134,7 +134,7 @@ public ResponseEntity executeClusterTerminateSessionEvent( } catch (Throwable t) { response = handleException(result, t); } - finishRequest(); + finishRequest(task, result); return response; } @@ -156,7 +156,7 @@ public ResponseEntity listUserSession() { response = handleException(result, t); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -174,7 +174,7 @@ public ResponseEntity getLocalSchedulerInformation() { response = handleException(result, t); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -192,7 +192,7 @@ public ResponseEntity stopLocalScheduler() { response = handleException(result, t); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -210,7 +210,7 @@ public ResponseEntity startLocalScheduler() { response = handleException(result, t); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -228,7 +228,7 @@ public ResponseEntity stopLocalTask(@PathVariable("oid") String oid) { response = handleException(result, t); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -255,7 +255,7 @@ public ResponseEntity getReportFile( } catch (Throwable t) { response = handleException(null, t); // we don't return the operation result } - finishRequest(); + finishRequest(task, result); return response; } @@ -281,7 +281,7 @@ public ResponseEntity deleteReportFile( } catch (Throwable t) { response = handleException(null, t); // we don't return the operation result } - finishRequest(); + finishRequest(task, result); return response; } @@ -300,7 +300,7 @@ public ResponseEntity getTask(@PathVariable("oid") String oid, @RequestParam( } catch (Throwable t) { response = handleException(null, t); // we don't return the operation result } - finishRequest(); + finishRequest(task, result); return response; } diff --git a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ExtensionSchemaRestController.java b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ExtensionSchemaRestController.java index 849eed6745e..49eb358430c 100644 --- a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ExtensionSchemaRestController.java +++ b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ExtensionSchemaRestController.java @@ -69,7 +69,7 @@ public ResponseEntity listSchemas() { .body(ex.getMessage()); // TODO handle this somehow better } - finishRequest(); + finishRequest(task, result); return response; } @@ -137,7 +137,7 @@ public ResponseEntity getSchema( response = handleException(result, ex); } - finishRequest(); + finishRequest(task, result); return response; } } diff --git a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ModelRestController.java b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ModelRestController.java index 68e62f92b2b..34cab2b8a1a 100644 --- a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ModelRestController.java +++ b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/ModelRestController.java @@ -72,19 +72,19 @@ public ResponseEntity generateValue( @RequestBody PolicyItemsDefinitionType policyItemsDefinition) { Task task = initRequest(); - OperationResult parentResult = createSubresult(task, "generateValue"); + OperationResult result = createSubresult(task, "generateValue"); Class clazz = ObjectTypes.getClassFromRestType(type); ResponseEntity response; try { - PrismObject object = model.getObject(clazz, oid, null, task, parentResult); - response = generateValue(object, policyItemsDefinition, task, parentResult); + PrismObject object = model.getObject(clazz, oid, null, task, result); + response = generateValue(object, policyItemsDefinition, task, result); } catch (Exception ex) { - parentResult.computeStatus(); - response = handleException(parentResult, ex); + result.computeStatus(); + response = handleException(result, ex); } - finishRequest(); + finishRequest(task, result); return response; } @@ -92,10 +92,10 @@ public ResponseEntity generateValue( public ResponseEntity generateValueRpc( @RequestBody PolicyItemsDefinitionType policyItemsDefinition) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("generateValueRpc"); + OperationResult result = task.getResult().createSubresult("generateValueRpc"); - ResponseEntity response = generateValue(null, policyItemsDefinition, task, parentResult); - finishRequest(); + ResponseEntity response = generateValue(null, policyItemsDefinition, task, result); + finishRequest(task, result); return response; } @@ -132,19 +132,19 @@ public ResponseEntity validateValue( @RequestBody PolicyItemsDefinitionType policyItemsDefinition) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("validateValue"); + OperationResult result = task.getResult().createSubresult("validateValue"); Class clazz = ObjectTypes.getClassFromRestType(type); ResponseEntity response; try { - PrismObject object = model.getObject(clazz, oid, null, task, parentResult); - response = validateValue(object, policyItemsDefinition, task, parentResult); + PrismObject object = model.getObject(clazz, oid, null, task, result); + response = validateValue(object, policyItemsDefinition, task, result); } catch (Exception ex) { - parentResult.computeStatus(); - response = handleException(parentResult, ex); + result.computeStatus(); + response = handleException(result, ex); } - finishRequest(); + finishRequest(task, result); return response; } @@ -152,42 +152,42 @@ public ResponseEntity validateValue( public ResponseEntity validateValue( @RequestBody PolicyItemsDefinitionType policyItemsDefinition) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("validateValue"); + OperationResult result = task.getResult().createSubresult("validateValue"); - ResponseEntity response = validateValue(null, policyItemsDefinition, task, parentResult); - finishRequest(); + ResponseEntity response = validateValue(null, policyItemsDefinition, task, result); + finishRequest(task, result); return response; } private ResponseEntity validateValue( PrismObject object, PolicyItemsDefinitionType policyItemsDefinition, - Task task, OperationResult parentResult) { + Task task, OperationResult result) { ResponseEntity response; if (policyItemsDefinition == null) { - response = createBadPolicyItemsDefinitionResponse("Policy items definition must not be null", parentResult); - finishRequest(); + response = createBadPolicyItemsDefinitionResponse("Policy items definition must not be null", result); + finishRequest(task, result); return response; } if (CollectionUtils.isEmpty(policyItemsDefinition.getPolicyItemDefinition())) { - response = createBadPolicyItemsDefinitionResponse("No definitions for items", parentResult); - finishRequest(); + response = createBadPolicyItemsDefinitionResponse("No definitions for items", result); + finishRequest(task, result); return response; } try { - modelInteraction.validateValue(object, policyItemsDefinition, task, parentResult); + modelInteraction.validateValue(object, policyItemsDefinition, task, result); - parentResult.computeStatusIfUnknown(); - if (parentResult.isAcceptable()) { - response = createResponse(HttpStatus.OK, policyItemsDefinition, parentResult, true); + result.computeStatusIfUnknown(); + if (result.isAcceptable()) { + response = createResponse(HttpStatus.OK, policyItemsDefinition, result, true); } else { - response = ResponseEntity.status(HttpStatus.CONFLICT).body(parentResult); + response = ResponseEntity.status(HttpStatus.CONFLICT).body(result); } } catch (Exception ex) { - parentResult.computeStatus(); - response = handleException(parentResult, ex); + result.computeStatus(); + response = handleException(result, ex); } return response; @@ -206,23 +206,23 @@ public ResponseEntity getValuePolicyForUser( logger.debug("getValuePolicyForUser start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("getValuePolicyForUser"); + OperationResult result = task.getResult().createSubresult("getValuePolicyForUser"); ResponseEntity response; try { Collection> options = SelectorOptions.createCollection(GetOperationOptions.createRaw()); - PrismObject user = model.getObject(UserType.class, oid, options, task, parentResult); + PrismObject user = model.getObject(UserType.class, oid, options, task, result); - CredentialsPolicyType policy = modelInteraction.getCredentialsPolicy(user, task, parentResult); + CredentialsPolicyType policy = modelInteraction.getCredentialsPolicy(user, task, result); - response = createResponse(HttpStatus.OK, policy, parentResult); + response = createResponse(HttpStatus.OK, policy, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); logger.debug("getValuePolicyForUser finish"); return response; @@ -239,7 +239,7 @@ public ResponseEntity getObject( logger.debug("model rest service for get operation start"); Task task = initRequest(); - OperationResult parentResult = createSubresult(task, "getObject"); + OperationResult result = createSubresult(task, "getObject"); Class clazz = ObjectTypes.getClassFromRestType(type); Collection> getOptions = @@ -254,7 +254,7 @@ public ResponseEntity getObject( ObjectQuery query = prismContext.queryFor(NodeType.class) .item(NodeType.F_NODE_IDENTIFIER).eq(nodeId) .build(); - List> objects = model.searchObjects(NodeType.class, query, getOptions, task, parentResult); + List> objects = model.searchObjects(NodeType.class, query, getOptions, task, result); if (objects.isEmpty()) { throw new ObjectNotFoundException("Current node (id " + nodeId + ") couldn't be found."); } else if (objects.size() > 1) { @@ -263,17 +263,17 @@ public ResponseEntity getObject( object = objects.get(0); } } else { - object = model.getObject(clazz, id, getOptions, task, parentResult); + object = model.getObject(clazz, id, getOptions, task, result); } removeExcludes(object, exclude); // temporary measure until fixed in repo - response = createResponse(HttpStatus.OK, object, parentResult); + response = createResponse(HttpStatus.OK, object, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -281,21 +281,21 @@ public ResponseEntity getObject( public ResponseEntity getSelf() { logger.debug("model rest service for get operation start"); Task task = initRequest(); - OperationResult parentResult = createSubresult(task, "self"); + OperationResult result = createSubresult(task, "self"); ResponseEntity response; try { - FocusType loggedInUser = SecurityUtil.getPrincipal().getFocus(); - PrismObject user = model.getObject(UserType.class, loggedInUser.getOid(), null, task, parentResult); - response = createResponse(HttpStatus.OK, user, parentResult, true); - parentResult.recordSuccessIfUnknown(); + String loggedInUserOid = SecurityUtil.getPrincipalOidIfAuthenticated(); + PrismObject user = model.getObject(UserType.class, loggedInUserOid, null, task, result); + response = createResponse(HttpStatus.OK, user, result, true); + result.recordSuccessIfUnknown(); } catch (SecurityViolationException | ObjectNotFoundException | SchemaException | CommunicationException | ConfigurationException | ExpressionEvaluationException e) { e.printStackTrace(); response = status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } - finishRequest(); + finishRequest(task, result); return response; } @@ -307,14 +307,14 @@ public ResponseEntity addObject( logger.debug("model rest service for add operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("addObject"); + OperationResult result = task.getResult().createSubresult("addObject"); Class clazz = ObjectTypes.getClassFromRestType(type); - if (!object.getCompileTimeClass().equals(clazz)) { - finishRequest(); - parentResult.recordFatalError("Request to add object of type " - + object.getCompileTimeClass().getSimpleName() + " to the collection of " + type); - return createErrorResponseBuilder(HttpStatus.BAD_REQUEST, parentResult); + if (object.getCompileTimeClass() == null || !object.getCompileTimeClass().equals(clazz)) { + String simpleName = object.getCompileTimeClass() != null ? object.getCompileTimeClass().getSimpleName() : null; + result.recordFatalError("Request to add object of type " + simpleName + " to the collection of " + type); + finishRequest(task, result); + return createErrorResponseBuilder(HttpStatus.BAD_REQUEST, result); } ModelExecuteOptions modelExecuteOptions = ModelExecuteOptions.fromRestOptions(options, prismContext); @@ -322,24 +322,24 @@ public ResponseEntity addObject( String oid; ResponseEntity response; try { - oid = model.addObject(object, modelExecuteOptions, task, parentResult); + oid = model.addObject(object, modelExecuteOptions, task, result); logger.debug("returned oid: {}", oid); if (oid != null) { response = createResponseWithLocation( clazz.isAssignableFrom(TaskType.class) ? HttpStatus.ACCEPTED : HttpStatus.CREATED, uriGetObject(type, oid), - parentResult); + result); } else { // OID might be null e.g. if the object creation is a subject of workflow approval - response = createResponse(HttpStatus.ACCEPTED, parentResult); + response = createResponse(HttpStatus.ACCEPTED, result); } } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -358,7 +358,7 @@ public ResponseEntity searchObjectsByType( @RequestParam(value = "exclude", required = false) List exclude, @RequestParam(value = "resolveNames", required = false) List resolveNames) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("searchObjectsByType"); + OperationResult result = task.getResult().createSubresult("searchObjectsByType"); //noinspection unchecked Class clazz = (Class) ObjectTypes.getClassFromRestType(type); @@ -368,19 +368,19 @@ public ResponseEntity searchObjectsByType( Collection> searchOptions = GetOperationOptions.fromRestOptions(options, include, exclude, resolveNames, DefinitionProcessingOption.ONLY_IF_EXISTS, prismContext); - List> objects = modelService.searchObjects(clazz, null, searchOptions, task, parentResult); + List> objects = modelService.searchObjects(clazz, null, searchOptions, task, result); ObjectListType listType = new ObjectListType(); for (PrismObject object : objects) { listType.getObject().add(object.asObjectable()); } - response = createResponse(HttpStatus.OK, listType, parentResult, true); + response = createResponse(HttpStatus.OK, listType, result, true); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -394,15 +394,15 @@ public ResponseEntity addObject( logger.debug("model rest service for add operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("addObject"); + OperationResult result = task.getResult().createSubresult("addObject"); Class clazz = ObjectTypes.getClassFromRestType(type); if (!object.getCompileTimeClass().equals(clazz)) { - finishRequest(); - parentResult.recordFatalError("Request to add object of type " + finishRequest(task, result); + result.recordFatalError("Request to add object of type " + object.getCompileTimeClass().getSimpleName() + " to the collection of " + type); - return createErrorResponseBuilder(HttpStatus.BAD_REQUEST, parentResult); + return createErrorResponseBuilder(HttpStatus.BAD_REQUEST, result); } ModelExecuteOptions modelExecuteOptions = ModelExecuteOptions.fromRestOptions(options, prismContext); @@ -416,19 +416,19 @@ public ResponseEntity addObject( String oid; ResponseEntity response; try { - oid = model.addObject(object, modelExecuteOptions, task, parentResult); + oid = model.addObject(object, modelExecuteOptions, task, result); logger.debug("returned oid : {}", oid); response = createResponseWithLocation( clazz.isAssignableFrom(TaskType.class) ? HttpStatus.ACCEPTED : HttpStatus.CREATED, uriGetObject(type, oid), - parentResult); + result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); + result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -441,32 +441,32 @@ public ResponseEntity deleteObject( logger.debug("model rest service for delete operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("deleteObject"); + OperationResult result = task.getResult().createSubresult("deleteObject"); Class clazz = ObjectTypes.getClassFromRestType(type); ResponseEntity response; try { if (clazz.isAssignableFrom(TaskType.class)) { - taskService.suspendAndDeleteTask(id, WAIT_FOR_TASK_STOP, true, task, parentResult); - parentResult.computeStatus(); - finishRequest(); - if (parentResult.isSuccess()) { + taskService.suspendAndDeleteTask(id, WAIT_FOR_TASK_STOP, true, task, result); + result.computeStatus(); + finishRequest(task, result); + if (result.isSuccess()) { return ResponseEntity.noContent().build(); } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(parentResult.getMessage()); + .body(result.getMessage()); } ModelExecuteOptions modelExecuteOptions = ModelExecuteOptions.fromRestOptions(options, prismContext); - model.deleteObject(clazz, id, modelExecuteOptions, task, parentResult); - response = createResponse(HttpStatus.NO_CONTENT, parentResult); + model.deleteObject(clazz, id, modelExecuteOptions, task, result); + response = createResponse(HttpStatus.NO_CONTENT, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -489,22 +489,22 @@ public ResponseEntity modifyObjectPatch( logger.debug("model rest service for modify operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("modifyObjectPatch"); + OperationResult result = task.getResult().createSubresult("modifyObjectPatch"); Class clazz = ObjectTypes.getClassFromRestType(type); ResponseEntity response; try { ModelExecuteOptions modelExecuteOptions = ModelExecuteOptions.fromRestOptions(options, prismContext); Collection modifications = DeltaConvertor.toModifications(modificationType, clazz, prismContext); - model.modifyObject(clazz, oid, modifications, modelExecuteOptions, task, parentResult); - response = createResponse(HttpStatus.NO_CONTENT, parentResult); + model.modifyObject(clazz, oid, modifications, modelExecuteOptions, task, result); + response = createResponse(HttpStatus.NO_CONTENT, result); } catch (Exception ex) { - parentResult.recordFatalError("Could not modify object. " + ex.getMessage(), ex); - response = handleException(parentResult, ex); + result.recordFatalError("Could not modify object. " + ex.getMessage(), ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -515,18 +515,18 @@ public ResponseEntity notifyChange( Validate.notNull(changeDescription, "Chnage description must not be null"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("notifyChange"); + OperationResult result = task.getResult().createSubresult("notifyChange"); ResponseEntity response; try { - modelService.notifyChange(changeDescription, task, parentResult); - response = createResponse(HttpStatus.OK, parentResult); + modelService.notifyChange(changeDescription, task, result); + response = createResponse(HttpStatus.OK, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -535,18 +535,18 @@ public ResponseEntity findShadowOwner( @PathVariable("oid") String shadowOid) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("findShadowOwner"); + OperationResult result = task.getResult().createSubresult("findShadowOwner"); ResponseEntity response; try { - PrismObject focus = modelService.searchShadowOwner(shadowOid, null, task, parentResult); - response = createResponse(HttpStatus.OK, focus, parentResult); + PrismObject focus = modelService.searchShadowOwner(shadowOid, null, task, result); + response = createResponse(HttpStatus.OK, focus, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -556,19 +556,19 @@ public ResponseEntity importShadow( logger.debug("model rest service for import shadow from resource operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("importShadow"); + OperationResult result = task.getResult().createSubresult("importShadow"); ResponseEntity response; try { - modelService.importFromResource(shadowOid, task, parentResult); + modelService.importFromResource(shadowOid, task, result); - response = createResponse(HttpStatus.OK, parentResult, parentResult); + response = createResponse(HttpStatus.OK, result, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -582,7 +582,7 @@ public ResponseEntity searchObjects( @RequestBody QueryType queryType) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("searchObjects"); + OperationResult result = task.getResult().createSubresult("searchObjects"); Class clazz = ObjectTypes.getClassFromRestType(type); ResponseEntity response; @@ -591,7 +591,7 @@ public ResponseEntity searchObjects( Collection> searchOptions = GetOperationOptions.fromRestOptions(options, include, exclude, resolveNames, DefinitionProcessingOption.ONLY_IF_EXISTS, prismContext); List> objects = - model.searchObjects(clazz, query, searchOptions, task, parentResult); + model.searchObjects(clazz, query, searchOptions, task, result); ObjectListType listType = new ObjectListType(); for (PrismObject o : objects) { @@ -599,13 +599,13 @@ public ResponseEntity searchObjects( listType.getObject().add(o.asObjectable()); } - response = createResponse(HttpStatus.OK, listType, parentResult, true); + response = createResponse(HttpStatus.OK, listType, result, true); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -622,22 +622,22 @@ public ResponseEntity importFromResource( logger.debug("model rest service for import from resource operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("importFromResource"); + OperationResult result = task.getResult().createSubresult("importFromResource"); QName objClass = new QName(MidPointConstants.NS_RI, objectClass); ResponseEntity response; try { - modelService.importFromResource(resourceOid, objClass, task, parentResult); + modelService.importFromResource(resourceOid, objClass, task, result); response = createResponseWithLocation( HttpStatus.SEE_OTHER, uriGetObject(ObjectTypes.TASK.getRestType(), task.getOid()), - parentResult); + result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - parentResult.computeStatus(); - finishRequest(); + result.computeStatus(); + finishRequest(task, result); return response; } @@ -647,22 +647,22 @@ public ResponseEntity testResource( logger.debug("model rest service for test resource operation start"); Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("testResource"); + OperationResult result = task.getResult().createSubresult("testResource"); ResponseEntity response; OperationResult testResult = null; try { testResult = modelService.testResource(resourceOid, task); - response = createResponse(HttpStatus.OK, testResult, parentResult); + response = createResponse(HttpStatus.OK, testResult, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } if (testResult != null) { - parentResult.getSubresults().add(testResult); + result.getSubresults().add(testResult); } - finishRequest(); + finishRequest(task, result); return response; } @@ -671,18 +671,18 @@ public ResponseEntity suspendTask( @PathVariable("oid") String taskOid) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("suspendTask"); + OperationResult result = task.getResult().createSubresult("suspendTask"); ResponseEntity response; try { - taskService.suspendTask(taskOid, WAIT_FOR_TASK_STOP, task, parentResult); - parentResult.computeStatus(); - response = createResponse(HttpStatus.NO_CONTENT, task, parentResult); + taskService.suspendTask(taskOid, WAIT_FOR_TASK_STOP, task, result); + result.computeStatus(); + response = createResponse(HttpStatus.NO_CONTENT, task, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - finishRequest(); + finishRequest(task, result); return response; } @@ -691,18 +691,18 @@ public ResponseEntity resumeTask( @PathVariable("oid") String taskOid) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("resumeTask"); + OperationResult result = task.getResult().createSubresult("resumeTask"); ResponseEntity response; try { - taskService.resumeTask(taskOid, task, parentResult); - parentResult.computeStatus(); - response = createResponse(HttpStatus.ACCEPTED, parentResult); + taskService.resumeTask(taskOid, task, result); + result.computeStatus(); + response = createResponse(HttpStatus.ACCEPTED, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - finishRequest(); + finishRequest(task, result); return response; } @@ -710,18 +710,18 @@ public ResponseEntity resumeTask( public ResponseEntity scheduleTaskNow( @PathVariable("oid") String taskOid) { Task task = initRequest(); - OperationResult parentResult = task.getResult().createSubresult("scheduleTaskNow"); + OperationResult result = task.getResult().createSubresult("scheduleTaskNow"); ResponseEntity response; try { - taskService.scheduleTaskNow(taskOid, task, parentResult); - parentResult.computeStatus(); - response = createResponse(HttpStatus.NO_CONTENT, parentResult); + taskService.scheduleTaskNow(taskOid, task, result); + result.computeStatus(); + response = createResponse(HttpStatus.NO_CONTENT, result); } catch (Exception ex) { - response = handleException(parentResult, ex); + response = handleException(result, ex); } - finishRequest(); + finishRequest(task, result); return response; } @@ -755,7 +755,7 @@ public ResponseEntity executeScript( response = handleExceptionNoLog(result, ex); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -785,7 +785,7 @@ public ResponseEntity compare( } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -804,7 +804,7 @@ public ResponseEntity getLogFileSize() { } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -831,7 +831,7 @@ public ResponseEntity getLog( } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -853,7 +853,7 @@ public ResponseEntity executeCredentialReset( } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -872,7 +872,7 @@ public ResponseEntity getThreadsDump() { response = handleExceptionNoLog(result, ex); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -891,7 +891,7 @@ public ResponseEntity getRunningTasksThreadsDump() { response = handleExceptionNoLog(result, ex); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } @@ -910,7 +910,7 @@ public ResponseEntity getTaskThreadsDump( response = handleExceptionNoLog(result, ex); } result.computeStatus(); - finishRequest(); + finishRequest(task, result); return response; } } From 715fabc4b64396ccdf44b651ca7d63aa881d536c Mon Sep 17 00:00:00 2001 From: lskublik Date: Mon, 28 Sep 2020 14:01:37 +0200 Subject: [PATCH 2/7] disabled logger for org.springframework.security.web.DefaultSecurityFilterChain --- .../initial-objects/000-system-configuration.xml | 8 +++++++- gui/admin-gui/src/main/resources/logback.xml | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/gui/admin-gui/src/main/resources/initial-objects/000-system-configuration.xml b/gui/admin-gui/src/main/resources/initial-objects/000-system-configuration.xml index b225fdf12b6..28e279da535 100644 --- a/gui/admin-gui/src/main/resources/initial-objects/000-system-configuration.xml +++ b/gui/admin-gui/src/main/resources/initial-objects/000-system-configuration.xml @@ -22,6 +22,12 @@ ERROR ro.isdc.wro.extensions.processor.css.Less4jProcessor + + + OFF + org.springframework.security.web.DefaultSecurityFilterChain + @@ -43,7 +49,7 @@ WARN org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl - + OFF org.hibernate.internal.ExceptionMapperStandardImpl diff --git a/gui/admin-gui/src/main/resources/logback.xml b/gui/admin-gui/src/main/resources/logback.xml index bbfb3427752..93eb58c9d70 100644 --- a/gui/admin-gui/src/main/resources/logback.xml +++ b/gui/admin-gui/src/main/resources/logback.xml @@ -55,6 +55,7 @@ + From 7d3f7f66d5eab4a5ead0c2a7ef53d514681b0368 Mon Sep 17 00:00:00 2001 From: lskublik Date: Mon, 28 Sep 2020 14:31:54 +0200 Subject: [PATCH 3/7] fix for principal non-null handling in AbstractRestController --- .../midpoint/rest/impl/AbstractRestController.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java index c08dd27b601..b612ce20190 100644 --- a/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java +++ b/model/rest-impl/src/main/java/com/evolveum/midpoint/rest/impl/AbstractRestController.java @@ -199,13 +199,15 @@ private void auditLogout(Task task, OperationResult result) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Object principal = authentication.getPrincipal(); - String name = null; + String name; + PrismObject user; if (principal instanceof MidPointPrincipal) { name = ((MidPointPrincipal) principal).getUsername(); - } else if (principal != null) { - return; // TODO Why exit if principal non-null and continue if principal is null? + user = ((MidPointPrincipal) principal).getFocus().asPrismObject(); + } else { + name = null; + user = null; } - PrismObject user = principal != null ? ((MidPointPrincipal) principal).getFocus().asPrismObject() : null; AuditEventRecord record = new AuditEventRecord(AuditEventType.TERMINATE_SESSION, AuditEventStage.REQUEST); record.setInitiator(user, prismContext); From 918e19fc68288e45ac3ab13b7d27c7eaf8983d0a Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Mon, 28 Sep 2020 14:59:29 +0200 Subject: [PATCH 4/7] optimize work with task tree in PolicyRuleSuspendTaskExecutor and OperationExecutionRecorder. --- .../model/api/context/ModelContext.java | 4 ++ .../midpoint/model/impl/lens/LensContext.java | 9 ++++ .../impl/lens/OperationExecutionRecorder.java | 42 ++++++++++++------- .../policy/PolicyRuleSuspendTaskExecutor.java | 2 +- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java index 606d5c52a02..a5486c33902 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelContext.java @@ -21,6 +21,8 @@ import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.ObjectTreeDeltas; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -109,4 +111,6 @@ default String dumpFocusPolicyRules(int indent) { Long getSequenceCounter(String sequenceOid); void setSequenceCounter(String sequenceOid, long counter); + + String getTaskTreeOid(Task task, OperationResult result); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java index 4fcbab38cf6..9b979a15def 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java @@ -218,6 +218,8 @@ public enum ExportType { @NotNull private transient final List operationApprovedBy = new ArrayList<>(); @NotNull private transient final List operationApproverComments = new ArrayList<>(); + private String taskTreeOid; + public LensContext(Class focusClass, PrismContext prismContext, ProvisioningService provisioningService) { Validate.notNull(prismContext, "No prismContext"); @@ -1725,4 +1727,11 @@ public boolean isExperimentalCodeEnabled() { return systemConfiguration != null && systemConfiguration.asObjectable().getInternals() != null && Boolean.TRUE.equals(systemConfiguration.asObjectable().getInternals().isEnableExperimentalCode()); } + + public String getTaskTreeOid(Task task, OperationResult result) throws SchemaException { + if (taskTreeOid == null) { + taskTreeOid = task.getTaskTreeId(result); + } + return taskTreeOid; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OperationExecutionRecorder.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OperationExecutionRecorder.java index 81c42589ffb..d1f3cafc615 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OperationExecutionRecorder.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/OperationExecutionRecorder.java @@ -108,8 +108,7 @@ private boolean recordFocusOperationExecution(LensContext List> executedDeltas = getExecutedDeltas(focusContext, (Class) objectNew.asObjectable().getClass(), clockworkException, result); LOGGER.trace("recordFocusOperationExecution: executedDeltas: {}", executedDeltas.size()); - return recordOperationExecution(objectNew, false, executedDeltas, now, context.getChannel(), - getSkipWhenSuccess(context), task, result); + return recordOperationExecution(context, objectNew, false, executedDeltas, now, task, result); } @NotNull @@ -149,16 +148,14 @@ private void recordProjectionOperationExecution(LensConte } List> executedDeltas = getExecutedDeltas(projectionContext, ShadowType.class, clockworkException, result); - recordOperationExecution(object, true, executedDeltas, now, - context.getChannel(), getSkipWhenSuccess(context), task, result); + recordOperationExecution(context, object, true, executedDeltas, now, task, result); } /** * @return true if the operation execution was recorded (or would be recorded, but skipped because of the configuration) */ - private boolean recordOperationExecution(PrismObject object, boolean deletedOk, - List> executedDeltas, XMLGregorianCalendar now, - String channel, boolean skipWhenSuccess, Task task, OperationResult result) + private boolean recordOperationExecution(LensContext context, PrismObject object, boolean deletedOk, + List> executedDeltas, XMLGregorianCalendar now, Task task, OperationResult result) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { OperationExecutionType operation = new OperationExecutionType(prismContext); OperationResult summaryResult = new OperationResult("recordOperationExecution"); @@ -176,10 +173,11 @@ private boolean recordOperationExecution(PrismObject o LOGGER.trace("recordOperationExecution: skipping because oid is null for object = {}", object); return false; } + createTaskRef(context, operation, task, result); summaryResult.computeStatus(); OperationResultStatusType overallStatus = summaryResult.getStatus().createStatusType(); - setOperationContext(operation, overallStatus, now, channel, task, result); - storeOperationExecution(object, oid, operation, deletedOk, skipWhenSuccess, result); + setOperationContext(operation, overallStatus, now, context.getChannel(), task); + storeOperationExecution(object, oid, operation, deletedOk, getSkipWhenSuccess(context), result); return true; } @@ -283,17 +281,31 @@ private void storeOperationExecution(@NotNull PrismObject } private void setOperationContext(OperationExecutionType operation, - OperationResultStatusType overallStatus, XMLGregorianCalendar now, String channel, Task task, OperationResult result) throws SchemaException { + OperationResultStatusType overallStatus, XMLGregorianCalendar now, String channel, Task task) { + + operation.setStatus(overallStatus); + operation.setInitiatorRef(ObjectTypeUtil.createObjectRef(task.getOwner(), prismContext)); // TODO what if the real initiator is different? (e.g. when executing approved changes) + operation.setChannel(channel); + operation.setTimestamp(now); + } + + private void createTaskRef(LensContext context, OperationExecutionType operation, Task task, OperationResult result) { if (task instanceof RunningTask && ((RunningTask) task).getParentForLightweightAsynchronousTask() != null) { task = ((RunningTask) task).getParentForLightweightAsynchronousTask(); } if (task.isPersistent()) { - operation.setTaskRef(ObjectTypeUtil.createObjectRef(task.getTaskTreeId(result), ObjectTypes.TASK)); + String taskOid; + try { + taskOid = context.getTaskTreeOid(task, result); + } catch (SchemaException e) { + //if something unexpeced happened, let's try current task oid + LOGGER.warn("Cannot get task tree oid, current task oid will be used, task: {}, \nreason: {}", task, e.getMessage(), e); + result.recordWarning("Cannot get task tree oid, current task oid will be used, task: " + task + "\nreason: " + e.getMessage(), e); + taskOid = task.getOid(); + } + + operation.setTaskRef(ObjectTypeUtil.createObjectRef(taskOid, ObjectTypes.TASK)); } - operation.setStatus(overallStatus); - operation.setInitiatorRef(ObjectTypeUtil.createObjectRef(task.getOwner(), prismContext)); // TODO what if the real initiator is different? (e.g. when executing approved changes) - operation.setChannel(channel); - operation.setTimestamp(now); } private ObjectDeltaOperationType createObjectDeltaOperation(LensObjectDeltaOperation deltaOperation) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleSuspendTaskExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleSuspendTaskExecutor.java index 09870360fea..deef0e46b28 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleSuspendTaskExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleSuspendTaskExecutor.java @@ -43,7 +43,7 @@ public void execute(@NotNull ModelContext context, Tas return; } - String id = task.getTaskTreeId(result); + String id = context.getTaskTreeOid(task, result); if (id == null) { LOGGER.trace("No persistent task context, no counting!"); return; From 1c5b8a13bb9b43101a3071c4a3e5593684fccf32 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Mon, 28 Sep 2020 14:56:58 +0200 Subject: [PATCH 5/7] MID-6361: Add timezone to xsd:DateTime if not present During parsing / creation XmlGregorianCalendar (xsd:DateTime) add local system timezone if timezone is not present. Current process is parse XmlGregorianCalendar, convert it to GregorianCalendar and then convert it to XmlGregorianCalendar again. Roundtrip via GregorianCalendar ensures that local timezone addition is same for: - converting from UNIX time (time millis) - converting from GregorianCalendar - fixing up missing timezone in XmlGregorianCalendar Signed-off-by: Tony Tkacik --- infra/prism-api/pom.xml | 17 +++++++++++++++++ .../midpoint/prism/xml/XmlTypeConverter.java | 12 +++++++++--- .../midpoint/schema/TestJaxbParsing.java | 4 ++-- .../midpoint/schema/TestParseGenericObject.java | 4 ++-- .../com/evolveum/midpoint/util/MiscUtil.java | 8 +------- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/infra/prism-api/pom.xml b/infra/prism-api/pom.xml index b7c16e4e06d..54639b26a5a 100644 --- a/infra/prism-api/pom.xml +++ b/infra/prism-api/pom.xml @@ -66,6 +66,23 @@ com.google.guava guava + + + + org.testng + testng + test + + + com.evolveum.midpoint.tools + test-ng + test + + + org.assertj + assertj-core + test + diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java index 8e9e55f0996..2b32d95d44f 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java @@ -16,6 +16,7 @@ import com.evolveum.midpoint.util.logging.TraceManager; import org.apache.commons.codec.binary.Base64; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.TestOnly; import org.w3c.dom.Element; import javax.xml.bind.annotation.XmlEnumValue; @@ -136,7 +137,9 @@ public static XMLGregorianCalendar createXMLGregorianCalendar(Date date) { } public static XMLGregorianCalendar createXMLGregorianCalendar(String string) { - return getDatatypeFactory().newXMLGregorianCalendar(string); + // FIXME: We need to make gregorian calendar roundtrip to make sure time zone is included + + return createXMLGregorianCalendar(getDatatypeFactory().newXMLGregorianCalendar(string)); } public static XMLGregorianCalendar createXMLGregorianCalendarFromIso8601(String iso8601string) { @@ -161,14 +164,16 @@ public static XMLGregorianCalendar createXMLGregorianCalendar(XMLGregorianCalend if (cal == null) { return null; } - return getDatatypeFactory().newXMLGregorianCalendar(cal.toGregorianCalendar()); // TODO find a better way + return createXMLGregorianCalendar(cal.toGregorianCalendar()); // TODO find a better way } + @TestOnly public static XMLGregorianCalendar createXMLGregorianCalendar(int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone) { return getDatatypeFactory().newXMLGregorianCalendar(year, month, day, hour, minute, second, millisecond, timezone); } + @TestOnly public static XMLGregorianCalendar createXMLGregorianCalendar(int year, int month, int day, int hour, int minute, int second) { return getDatatypeFactory().newXMLGregorianCalendar(year, month, day, hour, minute, second, 0, 0); @@ -477,7 +482,8 @@ public static T toJavaValue(String stringContent, Class type, boolean exc } else if (type.equals(GregorianCalendar.class)) { return (T) getDatatypeFactory().newXMLGregorianCalendar(stringContent).toGregorianCalendar(); } else if (XMLGregorianCalendar.class.isAssignableFrom(type)) { - return (T) getDatatypeFactory().newXMLGregorianCalendar(stringContent); + // MID-6361: We need to make XmlGregorian - Gregorian - XmlGregorian roundtrip to make sure time zone is includded + return (T) createXMLGregorianCalendar(stringContent); } else if (type.equals(ZonedDateTime.class)) { return (T) ZonedDateTime.parse(stringContent); } else if (Duration.class.isAssignableFrom(type)) { diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestJaxbParsing.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestJaxbParsing.java index 8ca2a2f008e..016b47815e1 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestJaxbParsing.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestJaxbParsing.java @@ -14,7 +14,6 @@ import java.io.File; import java.io.IOException; import javax.xml.bind.JAXBElement; -import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; @@ -27,6 +26,7 @@ import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.util.SchemaTestConstants; import com.evolveum.midpoint.util.exception.SchemaException; @@ -162,7 +162,7 @@ public void testParseGenericObjectFromJaxb() throws Exception { PrismAsserts.assertPropertyValue(extension, SchemaTestConstants.EXTENSION_INT_TYPE_ELEMENT, 1234); PrismAsserts.assertPropertyValue(extension, SchemaTestConstants.EXTENSION_DOUBLE_TYPE_ELEMENT, 456.789D); PrismAsserts.assertPropertyValue(extension, SchemaTestConstants.EXTENSION_LONG_TYPE_ELEMENT, 567890L); - XMLGregorianCalendar calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar("2002-05-30T09:10:11"); + XMLGregorianCalendar calendar = XmlTypeConverter.createXMLGregorianCalendar("2002-05-30T09:10:11"); PrismAsserts.assertPropertyValue(extension, SchemaTestConstants.EXTENSION_DATE_TYPE_ELEMENT, calendar); //todo locations ????? how to test DOM ?????? diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseGenericObject.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseGenericObject.java index 1336d690918..3f41abe5092 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseGenericObject.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseGenericObject.java @@ -11,7 +11,6 @@ import java.io.File; import java.util.Collection; import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; @@ -24,6 +23,7 @@ import com.evolveum.midpoint.prism.path.ItemName; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.schema.util.SchemaTestConstants; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.QNameUtil; @@ -138,7 +138,7 @@ private void assertGenericObject(PrismObject generic) throws PrismAsserts.assertPropertyValue(extensionContainerValue, SchemaTestConstants.EXTENSION_INT_TYPE_ELEMENT, 1234); PrismAsserts.assertPropertyValue(extensionContainerValue, SchemaTestConstants.EXTENSION_DOUBLE_TYPE_ELEMENT, 456.789D); PrismAsserts.assertPropertyValue(extensionContainerValue, SchemaTestConstants.EXTENSION_LONG_TYPE_ELEMENT, 567890L); - XMLGregorianCalendar calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar("2002-05-30T09:10:11"); + XMLGregorianCalendar calendar = XmlTypeConverter.createXMLGregorianCalendar("2002-05-30T09:10:11"); PrismAsserts.assertPropertyValue(extensionContainerValue, SchemaTestConstants.EXTENSION_DATE_TYPE_ELEMENT, calendar); } diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java b/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java index 84125fe0a95..3e082b13a43 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java @@ -280,13 +280,7 @@ public static boolean equals(Object a, Object b) { * this method will simply return null. */ public static @Nullable XMLGregorianCalendar asXMLGregorianCalendar(@Nullable Date date) { - if (date == null) { - return null; - } else { - GregorianCalendar gc = new GregorianCalendar(); - gc.setTimeInMillis(date.getTime()); - return DATATYPE_FACTORY.newXMLGregorianCalendar(gc); - } + return date == null ? null : asXMLGregorianCalendar(date.getTime()); } public static @Nullable XMLGregorianCalendar asXMLGregorianCalendar( From d182b23141b19050931c559b07f52ddf438fd79c Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 28 Sep 2020 15:10:52 +0200 Subject: [PATCH 6/7] Reflecting case outcome in pending delta (MID-6033) --- .../schema/util/OperationResultUtil.java | 7 ++ .../provisioning/impl/ShadowCache.java | 13 ++-- .../manual/AbstractManualResourceTest.java | 71 +++++++++++++++++++ .../src/test/resources/logback-test.xml | 4 +- .../test/resources/manual/account-fiasco.xml | 29 ++++++++ .../impl/builtin/ManualConnectorInstance.java | 18 +++-- .../test/AbstractIntegrationTest.java | 6 +- 7 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 provisioning/provisioning-impl/src/test/resources/manual/account-fiasco.xml diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/OperationResultUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/OperationResultUtil.java index 50b69d48edc..0997d8bca20 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/OperationResultUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/OperationResultUtil.java @@ -8,6 +8,7 @@ package com.evolveum.midpoint.schema.util; import com.evolveum.midpoint.prism.util.CloneUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; public class OperationResultUtil { @@ -47,4 +48,10 @@ public static OperationResultType shallowClone(OperationResultType result, boole } return clone; } + + public static boolean isSuccessful(OperationResultStatusType result) { + return OperationResultStatusType.SUCCESS.equals(result) || + OperationResultStatusType.HANDLED_ERROR.equals(result) || + OperationResultStatusType.WARNING.equals(result); + } } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 3ca4d33e6a5..31106fbdf05 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -39,10 +39,7 @@ import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.schema.util.ObjectQueryUtil; -import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.ResourceTypeUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.schema.util.*; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.DebugUtil; @@ -1447,6 +1444,7 @@ private PrismObject refreshShadowAsyncStatus(ProvisioningContext ctx List> notificationDeltas = new ArrayList<>(); boolean shadowInception = false; + OperationResultStatusType shadowInceptionOutcome = null; ObjectDelta shadowDelta = repoShadow.createModifyDelta(); for (PendingOperationType pendingOperation: sortedOperations) { @@ -1491,6 +1489,7 @@ private PrismObject refreshShadowAsyncStatus(ProvisioningContext ctx if (pendingDelta.isAdd()) { shadowInception = true; + shadowInceptionOutcome = pendingOperation.getResultStatus(); } if (pendingDelta.isDelete()) { @@ -1579,7 +1578,11 @@ private PrismObject refreshShadowAsyncStatus(ProvisioningContext ctx // attributes. We need this to "allocate" the identifiers, so iteration mechanism in the // model can find unique values while taking pending create operations into consideration. PropertyDelta existsDelta = shadowDelta.createPropertyModification(ShadowType.F_EXISTS); - existsDelta.setRealValuesToReplace(true); + if (OperationResultUtil.isSuccessful(shadowInceptionOutcome)) { + existsDelta.setRealValuesToReplace(true); + } else { + existsDelta.setRealValuesToReplace(false); + } shadowDelta.addModification(existsDelta); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java index 37d2c839f74..3d928434d8e 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/manual/AbstractManualResourceTest.java @@ -95,6 +95,9 @@ public abstract class AbstractManualResourceTest extends AbstractProvisioningInt protected static final String ACCOUNT_WILL_PASSWORD_OLD = "3lizab3th"; protected static final String ACCOUNT_WILL_PASSWORD_NEW = "ELIZAbeth"; + protected static final File ACCOUNT_FIASCO_FILE = new File(TEST_DIR, "account-fiasco.xml"); + protected static final String ACCOUNT_FIASCO_OID = "414dd45c-017f-11eb-acac-1760a547c740"; + protected static final String ATTR_USERNAME = "username"; protected static final QName ATTR_USERNAME_QNAME = new QName(MidPointConstants.NS_RI, ATTR_USERNAME); @@ -2362,6 +2365,74 @@ public void test320RefreshAccountWillAfter5min() throws Exception { assertCaseState(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); } + @Test + public void test500AddAccountFiasco() throws Exception { + // GIVEN + + Task givenTask = createTask(getTestName()); + OperationResult givenResult = givenTask.getResult(); + + PrismObject account = parseObject(ACCOUNT_FIASCO_FILE); + account.checkConsistence(); + + display("Adding shadow", account); + String addedObjectOid = provisioningService.addObject(account, null, null, givenTask, givenResult); + assertEquals(ACCOUNT_FIASCO_OID, addedObjectOid); + String fiascoCaseOid = assertInProgress(givenResult); + assertNotNull("No async reference in result", fiascoCaseOid); + + PrismObject repoShadow = assertRepoShadow(ACCOUNT_FIASCO_OID) + .assertConception() + .pendingOperations() + .singleOperation() + .assertId() + .assertType(PendingOperationTypeType.MANUAL) + .end() + .end() + .getObject(); + + assertCaseState(fiascoCaseOid, SchemaConstants.CASE_STATE_OPEN); + + XMLGregorianCalendar operationTimestampStart = clock.currentTimeXMLGregorianCalendar(); + + closeCase(fiascoCaseOid, OperationResultStatusType.FATAL_ERROR); + + Task task = getTestTask(); + OperationResult result = task.getResult(); + syncServiceMock.reset(); + + // WHEN + when(); + provisioningService.refreshShadow(repoShadow, null, task, result); + + // THEN + then(); + display(result); + assertSuccess(result); + + XMLGregorianCalendar operationTimestampEnd = clock.currentTimeXMLGregorianCalendar(); + + ShadowAsserter shadowRepoAsserter = assertRepoShadow(ACCOUNT_FIASCO_OID) + .assertIsNotExists() + .pendingOperations() + .singleOperation() + .assertId() + .assertType(PendingOperationTypeType.MANUAL) + .assertCompletionTimestamp(operationTimestampStart, operationTimestampEnd) + .assertExecutionStatus(PendingOperationExecutionStatusType.COMPLETED) + .assertResultStatus(OperationResultStatusType.FATAL_ERROR) + .end() + .end() + .assertNoPassword(); + + syncServiceMock.assertNoNotifyChange(); + syncServiceMock.assertSingleNotifySuccessOnly(); + + assertCaseState(fiascoCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + } + + // TODO: create, close case, then update backing store. // TODO: let grace period expire without updating the backing store (semi-manual-only) diff --git a/provisioning/provisioning-impl/src/test/resources/logback-test.xml b/provisioning/provisioning-impl/src/test/resources/logback-test.xml index 0990d14e1c6..54f43d4f1d4 100644 --- a/provisioning/provisioning-impl/src/test/resources/logback-test.xml +++ b/provisioning/provisioning-impl/src/test/resources/logback-test.xml @@ -38,7 +38,7 @@ - + @@ -49,7 +49,7 @@ - + diff --git a/provisioning/provisioning-impl/src/test/resources/manual/account-fiasco.xml b/provisioning/provisioning-impl/src/test/resources/manual/account-fiasco.xml new file mode 100644 index 00000000000..01edc121d0e --- /dev/null +++ b/provisioning/provisioning-impl/src/test/resources/manual/account-fiasco.xml @@ -0,0 +1,29 @@ + + + + + + ri:AccountObjectClass + account + + fiasco + Francesco Fiasco + + + enabled + + + + + DebaculoMAXIMO + + + + diff --git a/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java b/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java index 02096268abf..42d30a2a863 100644 --- a/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java +++ b/provisioning/ucf-impl-builtin/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/builtin/ManualConnectorInstance.java @@ -345,17 +345,23 @@ public OperationResultStatus queryOperationStatus(String asynchronousOperationRe // see CompleteWorkItemsAction.getOutcome(..) method private OperationResultStatus translateOutcome(String outcome) { - - // TODO: better algorithm if (outcome == null) { return null; - } else if (outcome.equals(OperationResultStatusType.SUCCESS.value())) { - return OperationResultStatus.SUCCESS; - } else if (SchemaConstants.MODEL_APPROVAL_OUTCOME_APPROVE.equals(outcome)) { + } + for (OperationResultStatusType statusType : OperationResultStatusType.values()) { + if (outcome.equals(statusType.value())) { + return OperationResultStatus.parseStatusType(statusType); + } + } + if (SchemaConstants.MODEL_APPROVAL_OUTCOME_APPROVE.equals(outcome)) { return OperationResultStatus.SUCCESS; - } else { + } else if (SchemaConstants.MODEL_APPROVAL_OUTCOME_REJECT.equals(outcome)) { + return OperationResultStatus.FATAL_ERROR; + } else if (SchemaConstants.MODEL_APPROVAL_OUTCOME_SKIP.equals(outcome)) { + // Better make this "unknown" than non-applicable. Non-applicable can be misinterpreted. return OperationResultStatus.UNKNOWN; } + return OperationResultStatus.UNKNOWN; } @Override diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index 54904143e45..67744c37af3 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -2218,6 +2218,10 @@ protected void assertCaseState(String oid, String expectedState) throws ObjectNo } protected void closeCase(String caseOid) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { + closeCase(caseOid, OperationResultStatusType.SUCCESS); + } + + protected void closeCase(String caseOid, OperationResultStatusType outcome) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { OperationResult result = new OperationResult("closeCase"); Collection modifications = new ArrayList<>(1); @@ -2228,7 +2232,7 @@ protected void closeCase(String caseOid) throws ObjectNotFoundException, SchemaE PrismPropertyDefinition outcomePropertyDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(CaseType.class).findPropertyDefinition(CaseType.F_OUTCOME); PropertyDelta outcomeDelta = outcomePropertyDef.createEmptyDelta(CaseType.F_OUTCOME); - outcomeDelta.setRealValuesToReplace(OperationResultStatusType.SUCCESS.value()); + outcomeDelta.setRealValuesToReplace(outcome.value()); modifications.add(outcomeDelta); repositoryService.modifyObject(CaseType.class, caseOid, modifications, null, result); From 1b8280939d560de63dbb7fe6c4dbc0433851fe84 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Mon, 28 Sep 2020 15:16:49 +0200 Subject: [PATCH 7/7] fixing test compilation --- .../midpoint/model/common/mapping/TestMappingMetadata.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingMetadata.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingMetadata.java index 6c3a61981a0..05fbce7a233 100644 --- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingMetadata.java +++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingMetadata.java @@ -1244,6 +1244,11 @@ public void setSequenceCounter(String sequenceOid, long counter) { public String debugDump(int indent) { return null; } + + @Override + public String getTaskTreeOid(Task task, OperationResult result) throws SchemaException { + return null; + } }; }