Skip to content

Commit

Permalink
MID-7523 fix for extension schema rest service + proper tests
Browse files Browse the repository at this point in the history
(cherry picked from commit 95170d7)
  • Loading branch information
1azyman committed Jan 17, 2022
1 parent 69cedb3 commit 28aa8ae
Show file tree
Hide file tree
Showing 6 changed files with 401 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23062,4 +23062,19 @@
</xsd:complexType>
<xsd:element name="plannedOperationAttempt" type="tns:PlannedOperationAttemptType"/>

<xsd:complexType name="SchemaFilesType">
<xsd:sequence>
<xsd:element name="schema" type="tns:SchemaFileType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:element name="schemaFiles" type="tns:SchemaFilesType"/>

<xsd:complexType name="SchemaFileType">
<xsd:sequence>
<xsd:element name="fileName" type="xsd:string"/>
<xsd:element name="namespace" type="xsd:string"/>
<xsd:element name="usualPrefix" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
4 changes: 4 additions & 0 deletions model/rest-impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,9 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
*/
package com.evolveum.midpoint.rest.impl;

import java.io.File;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.evolveum.midpoint.model.api.ModelAuthorizationAction;
import com.evolveum.midpoint.prism.schema.SchemaDescription;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters;
import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SchemaFileType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SchemaFilesType;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
Expand All @@ -22,25 +26,18 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.evolveum.midpoint.common.configuration.api.MidpointConfiguration;
import com.evolveum.midpoint.model.api.ModelAuthorizationAction;
import com.evolveum.midpoint.prism.schema.SchemaDescription;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters;
import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

@RestController
@RequestMapping({ "/ws/schema", "/rest/schema", "/api/schema" })
public class ExtensionSchemaRestController extends AbstractRestController {

@Autowired private SecurityEnforcer securityEnforcer;

@GetMapping(produces = MediaType.TEXT_PLAIN_VALUE)
@GetMapping
public ResponseEntity<?> listSchemas() {

Task task = initRequest();
OperationResult result = createSubresult(task, "listSchemas");

Expand All @@ -51,25 +48,30 @@ public ResponseEntity<?> listSchemas() {
SchemaRegistry registry = prismContext.getSchemaRegistry();
Collection<SchemaDescription> descriptions = registry.getSchemaDescriptions();

List<String> names = new ArrayList<>();
SchemaFilesType files = new SchemaFilesType();

for (SchemaDescription description : descriptions) {
String name = computeName(description);
if (name != null) {
names.add(name);

if (name == null) {
continue;
}

files.schema(new SchemaFileType()
.namespace(description.getNamespace())
.usualPrefix(description.getUsualPrefix())
.fileName(name));
}

String output = StringUtils.join(names, "\n");
response = ResponseEntity.ok(output);
response = ResponseEntity.ok(files);
} catch (Exception ex) {
// we can't use handleException because we cannot serialize OperationResultType into text/plain
LoggingUtils.logUnexpectedException(logger, "Got exception while servicing REST request: {}", ex, result.getOperation());
response = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ex.getMessage()); // TODO handle this somehow better
result.recordFatalError(ex);

response = handleException(result, ex);
}

finishRequest(task, result);

return response;
}

Expand All @@ -84,15 +86,11 @@ private String computeName(SchemaDescription description) {
return null;
}

String midpointHome = System.getProperty(MidpointConfiguration.MIDPOINT_HOME_PROPERTY);
java.nio.file.Path homePath = Paths.get(midpointHome, "schema");
java.nio.file.Path relative = homePath.relativize(file.toPath());

return relative.toString();
return file.getName();
}

@GetMapping(value = "/{name}",
produces = { MediaType.TEXT_XML_VALUE, MediaType.TEXT_PLAIN_VALUE })
produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_PLAIN_VALUE })
public ResponseEntity<?> getSchema(
@PathVariable("name") String name) {

Expand All @@ -105,11 +103,11 @@ public ResponseEntity<?> getSchema(
null, AuthorizationParameters.EMPTY, null, task, result);

if (name == null) {
response = ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.TEXT_PLAIN)
.body("Name not defined");
result.recordFatalError("Name not defined");
response = createErrorResponseBuilder(HttpStatus.BAD_REQUEST, result);
} else if (!name.toLowerCase().endsWith(".xsd") && name.length() > 4) {
response = ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.TEXT_PLAIN)
.body("Name must be an xsd schema (.xsd extension expected)");
result.recordFatalError("Name must be an xsd schema (.xsd extension expected)");
response = createErrorResponseBuilder(HttpStatus.BAD_REQUEST, result);
} else {
SchemaRegistry registry = prismContext.getSchemaRegistry();
Collection<SchemaDescription> descriptions = registry.getSchemaDescriptions();
Expand All @@ -124,16 +122,18 @@ public ResponseEntity<?> getSchema(
}

if (description != null) {
response = ResponseEntity.ok(new File(description.getPath()));
} else {
response = ResponseEntity
.status(HttpStatus.NOT_FOUND)
String content = FileUtils.readFileToString(new File(description.getPath()), StandardCharsets.UTF_8);
response = ResponseEntity.status(HttpStatus.OK)
.contentType(MediaType.TEXT_PLAIN)
.body("Unknown name");
.body(content);
} else {
result.recordFatalError("Unknown schema");
response = createErrorResponseBuilder(HttpStatus.NOT_FOUND, result);
}
}
} catch (Exception ex) {
result.computeStatus();
result.recordFatalError(ex);

response = handleException(result, ex);
}

Expand Down
4 changes: 4 additions & 0 deletions testing/rest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2010-2022 Evolveum
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.evolveum.midpoint.testing.rest;

import com.evolveum.midpoint.common.rest.MidpointAbstractProvider;
import com.evolveum.midpoint.gui.test.TestMidPointSpringApplication;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SchemaFileType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SchemaFilesType;

import org.apache.commons.io.FileUtils;
import org.apache.cxf.jaxrs.client.ClientConfiguration;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.provider.PrimitiveTextProvider;
import org.apache.cxf.transport.local.LocalConduit;
import org.testng.annotations.Test;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;

/**
* Created by Viliam Repan (lazyman).
*/
public class TestSchemaRestService extends RestServiceInitializer {

protected String ENDPOINT_ADDRESS = "http://localhost:"
+ TestMidPointSpringApplication.DEFAULT_PORT
+ System.getProperty("mp.test.rest.context.path", "/api/schema");

@Override
protected String getAcceptHeader() {
return null;
}

@Override
protected String getContentType() {
return null;
}

@Override
protected MidpointAbstractProvider getProvider() {
return null;
}

@Override
protected WebClient prepareClient(String username, String password) {
WebClient client = WebClient.create(ENDPOINT_ADDRESS, Arrays.asList(jsonProvider, new PrimitiveTextProvider<>()));
ClientConfiguration clientConfig = WebClient.getConfig(client);

clientConfig.getRequestContext().put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);

client.accept(MediaType.APPLICATION_JSON_TYPE);

createAuthorizationHeader(client, username, password);

return client;
}

private WebClient prepareClient() {
return prepareClient(USER_ADMINISTRATOR_USERNAME, USER_ADMINISTRATOR_PASSWORD);
}

@Test
public void test010listSchemas() {
WebClient client = prepareClient();

when();
Response response = client.get();

then();
assertStatus(response, 200);
SchemaFilesType schemas = response.readEntity(SchemaFilesType.class);
assertNotNull("Error response must contain list of schemas", schemas);
logger.info("Returned result: {}", schemas);

assertAndGetPiracySchemaFile(schemas);
}

private SchemaFileType assertAndGetPiracySchemaFile(SchemaFilesType schemas) {
assertNotNull("Schema file list must no be null", schemas);
assertEquals(1, schemas.getSchema().size());

SchemaFileType schemaFile = schemas.getSchema().get(0);
assertEquals("piracy.xsd", schemaFile.getFileName());
assertEquals("http://midpoint.evolveum.com/xml/ns/samples/piracy", schemaFile.getNamespace());
assertEquals(null, schemaFile.getUsualPrefix());

return schemaFile;
}

@Test
public void test020getSchema() throws IOException {
WebClient client = prepareClient();

when();
Response response = client.get();
SchemaFilesType schemas = response.readEntity(SchemaFilesType.class);
SchemaFileType file = assertAndGetPiracySchemaFile(schemas);

client.path("/" + file.getFileName());
client.accept(MediaType.TEXT_PLAIN_TYPE);
response = client.get();

then();
assertStatus(response, 200);
String content = response.readEntity(String.class);

String expected = FileUtils.readFileToString(new File("./src/test/resources/schema/piracy.xsd"), StandardCharsets.UTF_8);

assertEquals("Schemas doesn't match", expected, content);
}

@Test
public void test025getNonExistingSchema() {
WebClient client = prepareClient();

when();
client.path("/non-existing.xsd");
client.accept(MediaType.TEXT_PLAIN_TYPE, MediaType.APPLICATION_JSON_TYPE);

Response response = client.get();

then();
assertStatus(response, 404);
OperationResultType result = response.readEntity(OperationResultType.class);
assertNotNull("Error result must not be null", result);

assertFailure("Unknown schema", result);
}

@Test
public void test030getWrongExtensionSchema() {
WebClient client = prepareClient();

when();
client.path("/wrong-extension");
client.accept(MediaType.TEXT_PLAIN_TYPE, MediaType.APPLICATION_JSON_TYPE);

Response response = client.get();

then();
assertStatus(response, 400);
OperationResultType result = response.readEntity(OperationResultType.class);
assertNotNull("Error result must not be null", result);

assertFailure("Name must be an xsd schema (.xsd extension expected)", result);
}
}

0 comments on commit 28aa8ae

Please sign in to comment.