Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework dereferencing to make it strict and dereference shared designs in the ws #57

Merged
merged 1 commit into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import io.apicurio.datamodels.Library;
import io.apicurio.datamodels.core.models.Document;
import io.apicurio.hub.core.content.AbsoluteReferenceResolver;
import io.apicurio.hub.core.content.SharedReferenceResolver;
import io.apicurio.hub.core.exceptions.UnresolvableReferenceException;

/**
* Used to take a {@link Document} and convert it to its dereferenced
Expand All @@ -41,21 +43,28 @@ public class ContentDereferencer {
private AbsoluteReferenceResolver absoluteResolver;
@Inject
private InternalReferenceResolver apicurioResolver;
@Inject
private SharedReferenceResolver sharedReferenceResolver;

@PostConstruct
void init() {
Library.addReferenceResolver(apicurioResolver);
Library.addReferenceResolver(absoluteResolver);
Library.addReferenceResolver(sharedReferenceResolver);
}

/**
* Called to dereference the given content. Content must be in JSON format.
* @param content
* @throws IOException
*/
public String dereference(String content) throws IOException {
public String dereference(String content) throws UnresolvableReferenceException {
Document doc = Library.readDocumentFromJSONString(content);
doc = Library.dereferenceDocument(doc);
try {
doc = Library.dereferenceDocument(doc, true);
} catch (Exception e) {
throw new UnresolvableReferenceException(e);
}
return Library.writeDocumentToJSONString(doc);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import io.apicurio.hub.core.beans.CodegenProject;
import io.apicurio.hub.core.beans.CodegenProjectType;
import io.apicurio.hub.core.beans.Contributor;
import io.apicurio.hub.core.beans.DereferenceControlResult;
import io.apicurio.hub.core.beans.FormatType;
import io.apicurio.hub.core.beans.Invitation;
import io.apicurio.hub.core.beans.LinkedAccountType;
Expand All @@ -116,11 +117,13 @@
import io.apicurio.hub.core.cmd.OaiCommandException;
import io.apicurio.hub.core.cmd.OaiCommandExecutor;
import io.apicurio.hub.core.config.HubConfiguration;
import io.apicurio.hub.core.content.ContentAccessibilityAsserter;
import io.apicurio.hub.core.editing.IEditingSessionManager;
import io.apicurio.hub.core.exceptions.AccessDeniedException;
import io.apicurio.hub.core.exceptions.ApiValidationException;
import io.apicurio.hub.core.exceptions.NotFoundException;
import io.apicurio.hub.core.exceptions.ServerError;
import io.apicurio.hub.core.exceptions.UnresolvableReferenceException;
import io.apicurio.hub.core.integrations.ApicurioEventType;
import io.apicurio.hub.core.integrations.EventsService;
import io.apicurio.hub.core.storage.IStorage;
Expand Down Expand Up @@ -156,6 +159,8 @@ public class DesignsResource implements IDesignsResource {
@Inject
private ContentDereferencer dereferencer;
@Inject
private ContentAccessibilityAsserter accessibilityAsserter;
@Inject
private IEditingSessionManager editingSessionManager;
@Inject
private IMicrocksConnector microcks;
Expand Down Expand Up @@ -1125,7 +1130,7 @@ private String getApiContent(String designId, FormatType format, boolean derefer
}

return content;
} catch (StorageException | OaiCommandException | IOException e) {
} catch (StorageException | OaiCommandException | IOException | UnresolvableReferenceException e) {
throw new ServerError(e);
}
}
Expand Down Expand Up @@ -1440,7 +1445,7 @@ private String generateAndPublishProject(CodegenProject project, boolean updateO
} else {
throw new ServerError("Unsupported project type: " + project.getType());
}
} catch (IOException | SourceConnectorException e) {
} catch (IOException | SourceConnectorException | UnresolvableReferenceException e) {
throw new ServerError(e);
}
}
Expand Down Expand Up @@ -1585,6 +1590,15 @@ public SharingConfiguration configureSharing(String designId, UpdateSharingConfi
if (!this.authorizationService.hasOwnerPermission(currentUser, designId)) {
throw new NotFoundException();
}

if (SharingLevel.DOCUMENTATION == config.getLevel()) {
final ApiDesignContent document = this.storage.getLatestContentDocument(currentUser.getLogin(), designId);
final String content = document.getDocument();
final DereferenceControlResult dereferenceControlResult = accessibilityAsserter.isDereferenceable(content);
if (!dereferenceControlResult.isSuccess()) {
throw new ServerError(dereferenceControlResult.getError());
}
}

this.storage.setSharingConfig(designId, uuid, config.getLevel());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import io.apicurio.hub.core.beans.ApiDesignCollaborator;
import io.apicurio.hub.core.beans.ApiDesignCommand;
import io.apicurio.hub.core.beans.ApiDesignContent;
import io.apicurio.hub.core.beans.ApiDesignSharedContent;
import io.apicurio.hub.core.beans.ApiDesignType;
import io.apicurio.hub.core.beans.ApiMock;
import io.apicurio.hub.core.beans.ApiPublication;
Expand Down Expand Up @@ -297,7 +296,7 @@ public ApiDesignContent getContentDocumentForVersion(String designId, long conte
* @see io.apicurio.hub.core.storage.IStorage#getLatestContentDocumentForSharing(java.lang.String)
*/
@Override
public ApiDesignSharedContent getLatestContentDocumentForSharing(String sharingUuid)
public ApiDesignContent getLatestContentDocumentForSharing(String sharingUuid)
throws NotFoundException, StorageException {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2019 JBoss Inc
*
* 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 io.apicurio.hub.core.beans;

/**
* @author c.desc2@gmail.com
*/
public class DereferenceControlResult {

private boolean success = true;
private String error;

/**
* Constructor.
*/
public DereferenceControlResult() {
}

/**
* @return the success
*/
public boolean isSuccess() {
return success;
}

/**
* @param success the success to set
*/
public void setSuccess(boolean success) {
this.success = success;
}

/**
* @return the error
*/
public String getError() {
return error;
}

/**
* @param error the error to set
*/
public void setError(String error) {
this.error = error;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2019 JBoss Inc
*
* 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 io.apicurio.hub.core.content;

import io.apicurio.datamodels.Library;
import io.apicurio.datamodels.core.models.Document;
import io.apicurio.datamodels.core.util.ReferenceResolverChain;
import io.apicurio.hub.core.beans.DereferenceControlResult;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

/**
* Used to take a {@link Document} and check if it can be accessed from the hub-core package
* @author c.desc2@gmail.com
*/
@ApplicationScoped
public class ContentAccessibilityAsserter {

@Inject
private AbsoluteReferenceResolver absoluteResolver;
@Inject
private SharedReferenceResolver sharedReferenceResolver;

private final ReferenceResolverChain referenceResolverChain = new ReferenceResolverChain();

@PostConstruct
void init() {
referenceResolverChain.addResolver(absoluteResolver);
referenceResolverChain.addResolver(sharedReferenceResolver);
}

/**
* Checks whether the minimal reference resolvers can handle a document. Content must be in JSON format.
* @param content
* @return
*/
public DereferenceControlResult isDereferenceable(String content) {
final DereferenceControlResult res = new DereferenceControlResult();
try {
Document doc = Library.readDocumentFromJSONString(content);
Library.dereferenceDocument(doc, referenceResolverChain, true);
res.setSuccess(true);
} catch (Exception e) {
res.setError(e.getMessage());
res.setSuccess(false);
}
return res;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,35 @@
* limitations under the License.
*/

package io.apicurio.hub.editing.content;
package io.apicurio.hub.core.content;

import io.apicurio.datamodels.core.models.Node;
import io.apicurio.hub.core.beans.ApiDesignContent;
import io.apicurio.hub.core.content.AbstractReferenceResolver;
import io.apicurio.hub.core.beans.SharingConfiguration;
import io.apicurio.hub.core.exceptions.NotFoundException;
import io.apicurio.hub.core.storage.IStorage;
import io.apicurio.hub.core.storage.StorageException;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;

/**
* Resolves references that are local/internal to Apicurio using the permissions of a user. These references will be of the following form:
*
* apicurio:API_ID#/path/to/Entity
*
* An example of a valid local reference might be:
*
* apicurio:173827#/components/DataType
* Resolves an internal reference to a {@link Node} if the pointed resource is publicly shared.
*
* @author c.desc2@gmail.com
*/
public class UserScopedReferenceResolver extends AbstractReferenceResolver {
@ApplicationScoped
public class SharedReferenceResolver extends AbstractReferenceResolver {

@Inject
private IStorage storage;

private String userId;

/**
* Constructor.
*/
public UserScopedReferenceResolver(final IStorage storage, final String userId) {
this.storage = storage;
this.userId = userId;
public SharedReferenceResolver() {
}

/**
Expand All @@ -64,17 +59,17 @@ protected boolean accepts(URI uri) {
*/
@Override
protected String fetchUriContent(URI referenceUri) throws IOException {
final String designId = referenceUri.getSchemeSpecificPart();
try {
String apiId = referenceUri.getSchemeSpecificPart();
// TODO handle in-progress content? this code will ignore any changes not yet rolled up via the rollup executor
ApiDesignContent dc = storage.getLatestContentDocument(this.userId, apiId);
if (dc != null) {
return dc.getDocument();
final SharingConfiguration sharingConfig = storage.getSharingConfig(designId);
if (sharingConfig != null) {
final ApiDesignContent document = storage.getLatestContentDocumentForSharing(sharingConfig.getUuid());
return document.getDocument();
}
} catch (StorageException | NotFoundException e) {
return null;
} catch (NotFoundException | StorageException e) {
throw new IOException(e);
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,19 @@
* limitations under the License.
*/

package io.apicurio.hub.core.beans;
package io.apicurio.hub.core.exceptions;

/**
* @author c.desc2@gmail.com
*/
public class ApiDesignSharedContent extends ApiDesignContent {

private String createdBy;
public class UnresolvableReferenceException extends Exception {
private static final long serialVersionUID = 3091693573107649517L;

/**
* Constructor.
*/
public ApiDesignSharedContent() {
}

/**
* @return the createdBy
*/
public String getCreatedBy() {
return createdBy;
}

/**
* @param createdBy the createdBy to set
*/
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
public UnresolvableReferenceException(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import io.apicurio.hub.core.beans.ApiDesignCollaborator;
import io.apicurio.hub.core.beans.ApiDesignCommand;
import io.apicurio.hub.core.beans.ApiDesignContent;
import io.apicurio.hub.core.beans.ApiDesignSharedContent;
import io.apicurio.hub.core.beans.ApiDesignType;
import io.apicurio.hub.core.beans.ApiMock;
import io.apicurio.hub.core.beans.ApiPublication;
Expand Down Expand Up @@ -232,7 +231,7 @@ public interface IStorage {
* @throws NotFoundException
* @throws StorageException
*/
public ApiDesignSharedContent getLatestContentDocumentForSharing(String sharingUuid) throws NotFoundException, StorageException;
public ApiDesignContent getLatestContentDocumentForSharing(String sharingUuid) throws NotFoundException, StorageException;

/**
* Returns the full content row for the given API Design and content version.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public String selectLatestContentDocument() {
*/
@Override
public String selectLatestContentDocumentForSharing() {
return "SELECT c.*, s.created_by "
return "SELECT c.* "
+ "FROM api_content c "
+ "JOIN sharing s ON s.design_id = c.design_id "
+ "WHERE s.uuid = ? AND s.level = 'DOCUMENTATION' AND c.type = 0 "
Expand Down
Loading