| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.nifi.registry.web.service; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.nifi.registry.RegistryConfiguration; |
| import org.apache.nifi.registry.authorization.AccessPolicy; |
| import org.apache.nifi.registry.authorization.CurrentUser; |
| import org.apache.nifi.registry.authorization.Resource; |
| import org.apache.nifi.registry.authorization.User; |
| import org.apache.nifi.registry.authorization.UserGroup; |
| import org.apache.nifi.registry.bucket.Bucket; |
| import org.apache.nifi.registry.bucket.BucketItem; |
| import org.apache.nifi.registry.diff.VersionedFlowDifference; |
| import org.apache.nifi.registry.extension.bundle.Bundle; |
| import org.apache.nifi.registry.extension.bundle.BundleFilterParams; |
| import org.apache.nifi.registry.extension.bundle.BundleType; |
| import org.apache.nifi.registry.extension.bundle.BundleVersion; |
| import org.apache.nifi.registry.extension.bundle.BundleVersionFilterParams; |
| import org.apache.nifi.registry.extension.bundle.BundleVersionMetadata; |
| import org.apache.nifi.registry.extension.component.ExtensionFilterParams; |
| import org.apache.nifi.registry.extension.component.ExtensionMetadata; |
| import org.apache.nifi.registry.extension.component.TagCount; |
| import org.apache.nifi.registry.extension.component.manifest.Extension; |
| import org.apache.nifi.registry.extension.component.manifest.ProvidedServiceAPI; |
| import org.apache.nifi.registry.extension.repo.ExtensionRepoArtifact; |
| import org.apache.nifi.registry.extension.repo.ExtensionRepoBucket; |
| import org.apache.nifi.registry.extension.repo.ExtensionRepoExtensionMetadata; |
| import org.apache.nifi.registry.extension.repo.ExtensionRepoGroup; |
| import org.apache.nifi.registry.extension.repo.ExtensionRepoVersion; |
| import org.apache.nifi.registry.extension.repo.ExtensionRepoVersionSummary; |
| import org.apache.nifi.registry.flow.VersionedFlow; |
| import org.apache.nifi.registry.flow.VersionedFlowSnapshot; |
| import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; |
| import org.apache.nifi.registry.revision.api.InvalidRevisionException; |
| import org.apache.nifi.registry.revision.entity.RevisableEntity; |
| import org.apache.nifi.registry.revision.entity.RevisableEntityService; |
| import org.apache.nifi.registry.revision.entity.RevisionInfo; |
| import org.apache.nifi.registry.security.authorization.AuthorizableLookup; |
| import org.apache.nifi.registry.security.authorization.RequestAction; |
| import org.apache.nifi.registry.security.authorization.exception.AccessDeniedException; |
| import org.apache.nifi.registry.security.authorization.resource.Authorizable; |
| import org.apache.nifi.registry.security.authorization.resource.ResourceType; |
| import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils; |
| import org.apache.nifi.registry.service.AuthorizationService; |
| import org.apache.nifi.registry.service.RegistryService; |
| import org.apache.nifi.registry.service.extension.ExtensionService; |
| import org.apache.nifi.registry.web.link.LinkService; |
| import org.apache.nifi.registry.web.security.PermissionsService; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.stereotype.Service; |
| import org.springframework.transaction.annotation.Isolation; |
| import org.springframework.transaction.annotation.Transactional; |
| |
| import javax.ws.rs.core.Link; |
| import javax.ws.rs.core.StreamingOutput; |
| import javax.ws.rs.core.UriBuilder; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.UUID; |
| import java.util.function.Supplier; |
| import java.util.stream.Collectors; |
| |
| /** |
| * A wrapper around the service layer that applies validation, authorization, and revision management to all services. |
| * |
| * All REST resources should access the service layer through this facade. |
| */ |
| @Service |
| @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Throwable.class) |
| public class StandardServiceFacade implements ServiceFacade { |
| |
| private static final String INVALID_REVISION_MSG = "The %s you attempted to %s with id '%s' is out of date with the server. " + |
| "You may need to refresh your client and try again."; |
| |
| public static final String USER_GROUP_ENTITY_TYPE = "User Group"; |
| public static final String USER_ENTITY_TYPE = "User"; |
| public static final String ACCESS_POLICY_ENTITY_TYPE = "Access Policy"; |
| public static final String VERSIONED_FLOW_ENTITY_TYPE = "Versioned Flow"; |
| public static final String BUCKET_ENTITY_TYPE = "Bucket"; |
| |
| private final RegistryService registryService; |
| private final ExtensionService extensionService; |
| private final AuthorizationService authorizationService; |
| private final AuthorizableLookup authorizableLookup; |
| private final RevisableEntityService entityService; |
| private final RevisionFeature revisionFeature; |
| private final PermissionsService permissionsService; |
| private final LinkService linkService; |
| |
| @Autowired |
| public StandardServiceFacade(final RegistryService registryService, |
| final ExtensionService extensionService, |
| final AuthorizationService authorizationService, |
| final AuthorizableLookup authorizableLookup, |
| final RevisableEntityService entityService, |
| final RevisionFeature revisionFeature, |
| final PermissionsService permissionsService, |
| final LinkService linkService) { |
| this.registryService = registryService; |
| this.extensionService = extensionService; |
| this.authorizationService = authorizationService; |
| this.authorizableLookup = authorizableLookup; |
| this.entityService = entityService; |
| this.revisionFeature = revisionFeature; |
| this.permissionsService = permissionsService; |
| this.linkService = linkService; |
| } |
| |
| private String currentUserIdentity() { |
| return NiFiUserUtils.getNiFiUserIdentity(); |
| } |
| |
| // ---------------------- Bucket methods ---------------------------------------------- |
| |
| @Override |
| public Bucket createBucket(final Bucket bucket) { |
| authorizeBucketsAccess(RequestAction.WRITE); |
| validateCreationOfRevisableEntity(bucket, BUCKET_ENTITY_TYPE); |
| validateIdentifierNotPresent(bucket, BUCKET_ENTITY_TYPE); |
| |
| bucket.setIdentifier(UUID.randomUUID().toString()); |
| |
| final Bucket createdBucket = createRevisableEntity(bucket, BUCKET_ENTITY_TYPE, currentUserIdentity(), |
| () -> registryService.createBucket(bucket)); |
| permissionsService.populateBucketPermissions(createdBucket); |
| linkService.populateLinks(createdBucket); |
| return createdBucket; |
| } |
| |
| @Override |
| public Bucket getBucket(final String bucketIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final Bucket bucket = entityService.get(() -> registryService.getBucket(bucketIdentifier)); |
| permissionsService.populateBucketPermissions(bucket); |
| linkService.populateLinks(bucket); |
| return bucket; |
| } |
| |
| @Override |
| public List<Bucket> getBuckets() { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return Collections.emptyList(); |
| } |
| |
| final List<Bucket> buckets = entityService.getEntities(() -> registryService.getBuckets(authorizedBucketIds)); |
| permissionsService.populateBucketPermissions(buckets); |
| linkService.populateLinks(buckets); |
| return buckets; |
| } |
| |
| @Override |
| public Bucket updateBucket(final Bucket bucket) { |
| authorizeBucketAccess(RequestAction.WRITE, bucket.getIdentifier()); |
| validateUpdateOfRevisableEntity(bucket, BUCKET_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| registryService.verifyBucketExists(bucket.getIdentifier()); |
| |
| final Bucket updatedBucket = updateRevisableEntity(bucket, BUCKET_ENTITY_TYPE, currentUserIdentity(), |
| () -> registryService.updateBucket(bucket)); |
| permissionsService.populateBucketPermissions(updatedBucket); |
| linkService.populateLinks(updatedBucket); |
| return updatedBucket; |
| } |
| |
| @Override |
| public Bucket deleteBucket(final String bucketIdentifier, final RevisionInfo revisionInfo) { |
| authorizeBucketAccess(RequestAction.DELETE, bucketIdentifier); |
| validateDeleteOfRevisableEntity(bucketIdentifier, revisionInfo, BUCKET_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| registryService.verifyBucketExists(bucketIdentifier); |
| |
| return deleteRevisableEntity(bucketIdentifier, BUCKET_ENTITY_TYPE, revisionInfo, |
| () -> registryService.deleteBucket(bucketIdentifier)); |
| } |
| |
| // ---------------------- BucketItem methods ---------------------------------------------- |
| |
| @Override |
| public List<BucketItem> getBucketItems(final String bucketIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final List<BucketItem> items = registryService.getBucketItems(bucketIdentifier); |
| entityService.populateRevisions(items); |
| permissionsService.populateItemPermissions(items); |
| linkService.populateLinks(items); |
| return items; |
| } |
| |
| @Override |
| public List<BucketItem> getBucketItems() { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return new ArrayList<>(); |
| } |
| |
| final List<BucketItem> items = registryService.getBucketItems(authorizedBucketIds); |
| entityService.populateRevisions(items); |
| permissionsService.populateItemPermissions(items); |
| linkService.populateLinks(items); |
| return items; |
| } |
| |
| // ---------------------- Flow methods ---------------------------------------------- |
| |
| @Override |
| public VersionedFlow createFlow(final String bucketIdentifier, final VersionedFlow versionedFlow) { |
| authorizeBucketAccess(RequestAction.WRITE, bucketIdentifier); |
| validateCreationOfRevisableEntity(versionedFlow, VERSIONED_FLOW_ENTITY_TYPE); |
| |
| // NOTE: Don't validate that identifier is null... |
| // NiFi has been sending an identifier, so we must maintain backwards compatibility |
| if (versionedFlow.getIdentifier() == null) { |
| versionedFlow.setIdentifier(UUID.randomUUID().toString()); |
| } |
| |
| final VersionedFlow createdFlow = createRevisableEntity(versionedFlow, VERSIONED_FLOW_ENTITY_TYPE, currentUserIdentity(), |
| () -> registryService.createFlow(bucketIdentifier, versionedFlow)); |
| permissionsService.populateItemPermissions(createdFlow); |
| linkService.populateLinks(createdFlow); |
| return createdFlow; |
| } |
| |
| @Override |
| public VersionedFlow getFlow(final String bucketIdentifier, final String flowIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final VersionedFlow flow = entityService.get( |
| () -> registryService.getFlow(bucketIdentifier, flowIdentifier)); |
| permissionsService.populateItemPermissions(flow); |
| linkService.populateLinks(flow); |
| return flow; |
| } |
| |
| @Override |
| public VersionedFlow getFlow(final String flowIdentifier) { |
| final VersionedFlow flow = entityService.get(() -> registryService.getFlow(flowIdentifier)); |
| authorizeBucketAccess(RequestAction.READ, flow); |
| |
| permissionsService.populateItemPermissions(flow); |
| linkService.populateLinks(flow); |
| return flow; |
| } |
| |
| @Override |
| public List<VersionedFlow> getFlows(final String bucketIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final List<VersionedFlow> flows = entityService.getEntities(() -> registryService.getFlows(bucketIdentifier)); |
| permissionsService.populateItemPermissions(flows); |
| linkService.populateLinks(flows); |
| return flows; |
| } |
| |
| @Override |
| public VersionedFlow updateFlow(final VersionedFlow versionedFlow) { |
| authorizeBucketAccess(RequestAction.WRITE, versionedFlow); |
| validateUpdateOfRevisableEntity(versionedFlow, VERSIONED_FLOW_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| registryService.verifyFlowExists(versionedFlow.getIdentifier()); |
| |
| final VersionedFlow updatedFlow = updateRevisableEntity(versionedFlow, VERSIONED_FLOW_ENTITY_TYPE, currentUserIdentity(), |
| () -> registryService.updateFlow(versionedFlow)); |
| permissionsService.populateItemPermissions(updatedFlow); |
| linkService.populateLinks(updatedFlow); |
| return updatedFlow; |
| } |
| |
| @Override |
| public VersionedFlow deleteFlow(final String bucketIdentifier, final String flowIdentifier, final RevisionInfo revisionInfo) { |
| authorizeBucketAccess(RequestAction.DELETE, bucketIdentifier); |
| validateDeleteOfRevisableEntity(flowIdentifier, revisionInfo, VERSIONED_FLOW_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| registryService.verifyFlowExists(flowIdentifier); |
| |
| return deleteRevisableEntity(flowIdentifier, VERSIONED_FLOW_ENTITY_TYPE, revisionInfo, |
| () -> registryService.deleteFlow(bucketIdentifier, flowIdentifier)); |
| } |
| |
| // ---------------------- Flow Snapshot methods ---------------------------------------------- |
| |
| @Override |
| public VersionedFlowSnapshot createFlowSnapshot(final VersionedFlowSnapshot flowSnapshot) { |
| authorizeBucketAccess(RequestAction.WRITE, flowSnapshot); |
| |
| final VersionedFlowSnapshot createdSnapshot = registryService.createFlowSnapshot(flowSnapshot); |
| populateLinksAndPermissions(createdSnapshot); |
| return createdSnapshot; |
| } |
| |
| @Override |
| public VersionedFlowSnapshot getFlowSnapshot(final String bucketIdentifier, final String flowIdentifier, final Integer version) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final VersionedFlowSnapshot snapshot = registryService.getFlowSnapshot(bucketIdentifier, flowIdentifier, version); |
| populateLinksAndPermissions(snapshot); |
| return snapshot; |
| } |
| |
| @Override |
| public VersionedFlowSnapshot getFlowSnapshot(final String flowIdentifier, final Integer version) { |
| final VersionedFlowSnapshotMetadata latestMetadata = registryService.getLatestFlowSnapshotMetadata(flowIdentifier); |
| authorizeBucketAccess(RequestAction.READ, latestMetadata); |
| |
| final String bucketIdentifier = latestMetadata.getBucketIdentifier(); |
| final VersionedFlowSnapshot snapshot = registryService.getFlowSnapshot(bucketIdentifier, flowIdentifier, version); |
| populateLinksAndPermissions(snapshot); |
| return snapshot; |
| } |
| |
| @Override |
| public VersionedFlowSnapshot getLatestFlowSnapshot(final String bucketIdentifier, final String flowIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final VersionedFlowSnapshotMetadata latestMetadata = getLatestFlowSnapshotMetadata(bucketIdentifier, flowIdentifier); |
| final VersionedFlowSnapshot lastSnapshot = getFlowSnapshot(bucketIdentifier, flowIdentifier, latestMetadata.getVersion()); |
| populateLinksAndPermissions(lastSnapshot); |
| return lastSnapshot; |
| } |
| |
| @Override |
| public VersionedFlowSnapshot getLatestFlowSnapshot(final String flowIdentifier) { |
| final VersionedFlowSnapshotMetadata latestMetadata = registryService.getLatestFlowSnapshotMetadata(flowIdentifier); |
| authorizeBucketAccess(RequestAction.READ, latestMetadata); |
| |
| final String bucketIdentifier = latestMetadata.getBucketIdentifier(); |
| final Integer latestVersion = latestMetadata.getVersion(); |
| |
| final VersionedFlowSnapshot lastSnapshot = registryService.getFlowSnapshot(bucketIdentifier, flowIdentifier, latestVersion); |
| populateLinksAndPermissions(lastSnapshot); |
| return lastSnapshot; |
| } |
| |
| @Override |
| public SortedSet<VersionedFlowSnapshotMetadata> getFlowSnapshots(final String bucketIdentifier, final String flowIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final SortedSet<VersionedFlowSnapshotMetadata> snapshots = registryService.getFlowSnapshots(bucketIdentifier, flowIdentifier); |
| linkService.populateLinks(snapshots); |
| return snapshots; |
| } |
| |
| @Override |
| public SortedSet<VersionedFlowSnapshotMetadata> getFlowSnapshots(final String flowIdentifier) { |
| final VersionedFlow flow = registryService.getFlow(flowIdentifier); |
| authorizeBucketAccess(RequestAction.READ, flow); |
| |
| final String bucketIdentifier = flow.getBucketIdentifier(); |
| final SortedSet<VersionedFlowSnapshotMetadata> snapshots = registryService.getFlowSnapshots(bucketIdentifier, flowIdentifier); |
| linkService.populateLinks(snapshots); |
| return snapshots; |
| } |
| |
| @Override |
| public VersionedFlowSnapshotMetadata getLatestFlowSnapshotMetadata(final String bucketIdentifier, final String flowIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final VersionedFlowSnapshotMetadata latest = registryService.getLatestFlowSnapshotMetadata(bucketIdentifier, flowIdentifier); |
| linkService.populateLinks(latest); |
| return latest; |
| } |
| |
| @Override |
| public VersionedFlowSnapshotMetadata getLatestFlowSnapshotMetadata(final String flowIdentifier) { |
| final VersionedFlowSnapshotMetadata latest = registryService.getLatestFlowSnapshotMetadata(flowIdentifier); |
| authorizeBucketAccess(RequestAction.READ, latest); |
| |
| linkService.populateLinks(latest); |
| return latest; |
| } |
| |
| @Override |
| public VersionedFlowDifference getFlowDiff(final String bucketIdentifier, final String flowIdentifier, final Integer versionA, final Integer versionB) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| return registryService.getFlowDiff(bucketIdentifier, flowIdentifier, versionA, versionB); |
| } |
| |
| private void populateLinksAndPermissions(final VersionedFlowSnapshot snapshot) { |
| if (snapshot == null) { |
| return; |
| } |
| |
| if (snapshot.getSnapshotMetadata() != null) { |
| linkService.populateLinks(snapshot.getSnapshotMetadata()); |
| } |
| |
| if (snapshot.getFlow() != null) { |
| linkService.populateLinks(snapshot.getFlow()); |
| } |
| |
| if (snapshot.getBucket() != null) { |
| permissionsService.populateBucketPermissions(snapshot.getBucket()); |
| linkService.populateLinks(snapshot.getBucket()); |
| } |
| } |
| |
| // ---------------------- Bundle methods ---------------------------------------------- |
| |
| @Override |
| public List<Bundle> getBundles(final BundleFilterParams filterParams) { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return new ArrayList<>(); |
| } |
| |
| final List<Bundle> bundles = extensionService.getBundles(authorizedBucketIds, filterParams); |
| permissionsService.populateItemPermissions(bundles); |
| linkService.populateLinks(bundles); |
| return bundles; |
| } |
| |
| @Override |
| public List<Bundle> getBundlesByBucket(final String bucketIdentifier) { |
| authorizeBucketAccess(RequestAction.READ, bucketIdentifier); |
| |
| final List<Bundle> bundles = extensionService.getBundlesByBucket(bucketIdentifier); |
| permissionsService.populateItemPermissions(bundles); |
| linkService.populateLinks(bundles); |
| return bundles; |
| } |
| |
| @Override |
| public Bundle getBundle(final String bundleIdentifier) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| permissionsService.populateItemPermissions(bundle); |
| linkService.populateLinks(bundle); |
| return bundle; |
| } |
| |
| @Override |
| public Bundle deleteBundle(final String bundleIdentifier) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| authorizeBucketAccess(RequestAction.DELETE, bundle); |
| |
| final Bundle deletedBundle = extensionService.deleteBundle(bundle); |
| permissionsService.populateItemPermissions(deletedBundle); |
| linkService.populateLinks(deletedBundle); |
| return deletedBundle; |
| } |
| |
| // ---------------------- Bundle Version methods ---------------------------------------------- |
| |
| @Override |
| public BundleVersion createBundleVersion(final String bucketIdentifier, final BundleType bundleType, |
| final InputStream inputStream, final String clientSha256) throws IOException { |
| |
| authorizeBucketAccess(RequestAction.WRITE, bucketIdentifier); |
| |
| final BundleVersion createdBundleVersion = extensionService.createBundleVersion( |
| bucketIdentifier, bundleType, inputStream, clientSha256); |
| |
| linkService.populateLinks(createdBundleVersion.getVersionMetadata()); |
| linkService.populateLinks(createdBundleVersion.getBundle()); |
| linkService.populateLinks(createdBundleVersion.getBucket()); |
| |
| permissionsService.populateItemPermissions(createdBundleVersion.getBundle()); |
| |
| return createdBundleVersion; |
| } |
| |
| @Override |
| public SortedSet<BundleVersionMetadata> getBundleVersions(final BundleVersionFilterParams filterParams) { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return Collections.emptySortedSet(); |
| } |
| |
| final SortedSet<BundleVersionMetadata> bundleVersions = extensionService.getBundleVersions(authorizedBucketIds, filterParams); |
| linkService.populateLinks(bundleVersions); |
| return bundleVersions; |
| } |
| |
| @Override |
| public SortedSet<BundleVersionMetadata> getBundleVersions(final String bundleIdentifier) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final SortedSet<BundleVersionMetadata> bundleVersions = extensionService.getBundleVersions(bundleIdentifier); |
| linkService.populateLinks(bundleVersions); |
| return bundleVersions; |
| } |
| |
| @Override |
| public BundleVersion getBundleVersion(final String bundleIdentifier, final String version) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| linkService.populateLinks(bundleVersion); |
| return bundleVersion; |
| } |
| |
| @Override |
| public StreamingContent getBundleVersionContent(final String bundleIdentifier, final String version) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| |
| final StreamingOutput streamingOutput = (output) -> extensionService.writeBundleVersionContent(bundleVersion, output); |
| return new StreamingContent(streamingOutput, bundleVersion.getFilename()); |
| } |
| |
| @Override |
| public BundleVersion deleteBundleVersion(final String bundleIdentifier, final String version) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| authorizeBucketAccess(RequestAction.DELETE, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| |
| final BundleVersion deletedBundleVersion = extensionService.deleteBundleVersion(bundleVersion); |
| linkService.populateLinks(deletedBundleVersion); |
| return deletedBundleVersion; |
| } |
| |
| // ---------------------- Extension methods ---------------------------------------------- |
| |
| @Override |
| public SortedSet<ExtensionMetadata> getExtensionMetadata(final ExtensionFilterParams filterParams) { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return Collections.emptySortedSet(); |
| } |
| |
| final SortedSet<ExtensionMetadata> metadata = extensionService.getExtensionMetadata(authorizedBucketIds, filterParams); |
| linkService.populateLinks(metadata); |
| return metadata; |
| } |
| |
| @Override |
| public SortedSet<ExtensionMetadata> getExtensionMetadata(final ProvidedServiceAPI serviceAPI) { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return Collections.emptySortedSet(); |
| } |
| |
| final SortedSet<ExtensionMetadata> metadata = extensionService.getExtensionMetadata(authorizedBucketIds, serviceAPI); |
| linkService.populateLinks(metadata); |
| return metadata; |
| } |
| |
| @Override |
| public SortedSet<ExtensionMetadata> getExtensionMetadata(final String bundleIdentifier, final String version) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| |
| final SortedSet<ExtensionMetadata> extensions = extensionService.getExtensionMetadata(bundleVersion); |
| linkService.populateLinks(extensions); |
| return extensions; |
| } |
| |
| @Override |
| public Extension getExtension(final String bundleIdentifier, final String version, final String name) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| return extensionService.getExtension(bundleVersion, name); |
| } |
| |
| @Override |
| public StreamingOutput getExtensionDocs(final String bundleIdentifier, final String version, final String name) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| |
| final StreamingOutput streamingOutput = (output) -> extensionService.writeExtensionDocs(bundleVersion, name, output); |
| return streamingOutput; |
| } |
| |
| @Override |
| public StreamingOutput getAdditionalDetailsDocs(final String bundleIdentifier, final String version, final String name) { |
| final Bundle bundle = extensionService.getBundle(bundleIdentifier); |
| authorizeBucketAccess(RequestAction.READ, bundle); |
| |
| final String bucketIdentifier = bundle.getBucketIdentifier(); |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucketIdentifier, bundleIdentifier, version); |
| |
| final StreamingOutput streamingOutput = (output) -> extensionService.writeAdditionalDetailsDocs(bundleVersion, name, output); |
| return streamingOutput; |
| } |
| |
| @Override |
| public SortedSet<TagCount> getExtensionTags() { |
| return extensionService.getExtensionTags(); |
| } |
| |
| // ---------------------- Extension Repository methods ---------------------------------------------- |
| |
| @Override |
| public SortedSet<ExtensionRepoBucket> getExtensionRepoBuckets(final URI baseUri) { |
| final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); |
| if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { |
| // not authorized for any bucket, return empty list of items |
| return Collections.emptySortedSet(); |
| } |
| |
| final SortedSet<ExtensionRepoBucket> repoBuckets = extensionService.getExtensionRepoBuckets(authorizedBucketIds); |
| linkService.populateFullLinks(repoBuckets, baseUri); |
| return repoBuckets; |
| } |
| |
| @Override |
| public SortedSet<ExtensionRepoGroup> getExtensionRepoGroups(final URI baseUri, final String bucketName) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final SortedSet<ExtensionRepoGroup> repoGroups = extensionService.getExtensionRepoGroups(bucket); |
| linkService.populateFullLinks(repoGroups, baseUri); |
| return extensionService.getExtensionRepoGroups(bucket); |
| } |
| |
| @Override |
| public SortedSet<ExtensionRepoArtifact> getExtensionRepoArtifacts(final URI baseUri, final String bucketName, final String groupId) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final SortedSet<ExtensionRepoArtifact> repoArtifacts = extensionService.getExtensionRepoArtifacts(bucket, groupId); |
| linkService.populateFullLinks(repoArtifacts, baseUri); |
| return repoArtifacts; |
| } |
| |
| @Override |
| public SortedSet<ExtensionRepoVersionSummary> getExtensionRepoVersions(final URI baseUri, final String bucketName, final String groupId, |
| final String artifactId) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final SortedSet<ExtensionRepoVersionSummary> repoVersions = extensionService.getExtensionRepoVersions(bucket, groupId, artifactId); |
| linkService.populateFullLinks(repoVersions, baseUri); |
| return repoVersions; |
| } |
| |
| @Override |
| public ExtensionRepoVersion getExtensionRepoVersion(final URI baseUri, final String bucketName, final String groupId, |
| final String artifactId, final String version) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| |
| final String extensionsUri = generateResourceUri(baseUri, |
| "extension-repository", |
| bundleVersion.getBucket().getName(), |
| bundleVersion.getBundle().getGroupId(), |
| bundleVersion.getBundle().getArtifactId(), |
| bundleVersion.getVersionMetadata().getVersion(), |
| "extensions"); |
| |
| final String downloadUri = generateResourceUri(baseUri, |
| "extension-repository", |
| bundleVersion.getBucket().getName(), |
| bundleVersion.getBundle().getGroupId(), |
| bundleVersion.getBundle().getArtifactId(), |
| bundleVersion.getVersionMetadata().getVersion(), |
| "content"); |
| |
| final String sha256Uri = generateResourceUri(baseUri, |
| "extension-repository", |
| bundleVersion.getBucket().getName(), |
| bundleVersion.getBundle().getGroupId(), |
| bundleVersion.getBundle().getArtifactId(), |
| bundleVersion.getVersionMetadata().getVersion(), |
| "sha256"); |
| |
| final ExtensionRepoVersion repoVersion = new ExtensionRepoVersion(); |
| repoVersion.setExtensionsLink(Link.fromUri(extensionsUri).rel("extensions").build()); |
| repoVersion.setDownloadLink(Link.fromUri(downloadUri).rel("content").build()); |
| repoVersion.setSha256Link(Link.fromUri(sha256Uri).rel("sha256").build()); |
| repoVersion.setSha256Supplied(bundleVersion.getVersionMetadata().getSha256Supplied()); |
| return repoVersion; |
| } |
| |
| @Override |
| public StreamingContent getExtensionRepoVersionContent(final String bucketName, final String groupId, final String artifactId, |
| final String version) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| final StreamingOutput streamingOutput = (output) -> extensionService.writeBundleVersionContent(bundleVersion, output); |
| return new StreamingContent(streamingOutput, bundleVersion.getFilename()); |
| } |
| |
| @Override |
| public String getExtensionRepoVersionSha256(final String bucketName, final String groupId, final String artifactId, |
| final String version) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| final String sha256Hex = bundleVersion.getVersionMetadata().getSha256(); |
| return sha256Hex; |
| } |
| |
| @Override |
| public List<ExtensionRepoExtensionMetadata> getExtensionRepoExtensions(final URI baseUri, final String bucketName, final String groupId, |
| final String artifactId, final String version) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| final SortedSet<ExtensionMetadata> extensions = extensionService.getExtensionMetadata(bundleVersion); |
| |
| final List<ExtensionRepoExtensionMetadata> extensionRepoExtensions = new ArrayList<>(extensions.size()); |
| extensions.forEach(e -> extensionRepoExtensions.add(new ExtensionRepoExtensionMetadata(e))); |
| linkService.populateFullLinks(extensionRepoExtensions, baseUri); |
| return extensionRepoExtensions; |
| } |
| |
| @Override |
| public Extension getExtensionRepoExtension(final URI baseUri, final String bucketName, final String groupId, |
| final String artifactId, final String version, final String extensionName) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| final Extension extension = extensionService.getExtension(bundleVersion, extensionName); |
| return extension; |
| } |
| |
| @Override |
| public StreamingOutput getExtensionRepoExtensionDocs(final URI baseUri, final String bucketName, final String groupId, |
| final String artifactId, final String version, final String extensionName) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| final StreamingOutput streamingOutput = (output) -> extensionService.writeExtensionDocs(bundleVersion, extensionName, output); |
| return streamingOutput; |
| } |
| |
| @Override |
| public StreamingOutput getExtensionRepoExtensionAdditionalDocs(final URI baseUri, final String bucketName, final String groupId, |
| final String artifactId, final String version, final String extensionName) { |
| final Bucket bucket = registryService.getBucketByName(bucketName); |
| authorizeBucketAccess(RequestAction.READ, bucket.getIdentifier()); |
| |
| final BundleVersion bundleVersion = extensionService.getBundleVersion(bucket.getIdentifier(), groupId, artifactId, version); |
| final StreamingOutput streamingOutput = (output) -> extensionService.writeAdditionalDetailsDocs(bundleVersion, extensionName, output); |
| return streamingOutput; |
| } |
| |
| |
| // ---------------------- Field methods ---------------------------------------------- |
| |
| @Override |
| public Set<String> getBucketFields() { |
| return registryService.getBucketFields(); |
| } |
| |
| @Override |
| public Set<String> getBucketItemFields() { |
| return registryService.getBucketItemFields(); |
| } |
| |
| @Override |
| public Set<String> getFlowFields() { |
| return registryService.getFlowFields(); |
| } |
| |
| // ---------------------- User methods ---------------------------------------------- |
| |
| @Override |
| public User createUser(final User user) { |
| verifyAuthorizerSupportsConfigurableUserGroups(); |
| authorizeTenantsAccess(RequestAction.WRITE); |
| validateCreationOfRevisableEntity(user, USER_ENTITY_TYPE); |
| validateIdentifierNotPresent(user, USER_ENTITY_TYPE); |
| |
| user.setIdentifier(UUID.randomUUID().toString()); |
| return createRevisableEntity(user, USER_ENTITY_TYPE, currentUserIdentity(), () -> authorizationService.createUser(user)); |
| } |
| |
| @Override |
| public List<User> getUsers() { |
| verifyAuthorizerIsManaged(); |
| authorizeTenantsAccess(RequestAction.READ); |
| return entityService.getEntities(() -> authorizationService.getUsers()); |
| } |
| |
| @Override |
| public User getUser(final String identifier) { |
| verifyAuthorizerIsManaged(); |
| authorizeTenantsAccess(RequestAction.READ); |
| return entityService.get(() -> authorizationService.getUser(identifier)); |
| } |
| |
| @Override |
| public User updateUser(final User user) { |
| verifyAuthorizerSupportsConfigurableUserGroups(); |
| authorizeTenantsAccess(RequestAction.WRITE); |
| validateUpdateOfRevisableEntity(user, USER_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| authorizationService.verifyUserExists(user.getIdentifier()); |
| |
| return updateRevisableEntity(user, USER_ENTITY_TYPE, currentUserIdentity(), () -> authorizationService.updateUser(user)); |
| } |
| |
| @Override |
| public User deleteUser(final String identifier, final RevisionInfo revisionInfo) { |
| verifyAuthorizerSupportsConfigurableUserGroups(); |
| authorizeTenantsAccess(RequestAction.DELETE); |
| validateDeleteOfRevisableEntity(identifier, revisionInfo, USER_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| authorizationService.verifyUserExists(identifier); |
| |
| return deleteRevisableEntity(identifier, USER_ENTITY_TYPE, revisionInfo, () -> authorizationService.deleteUser(identifier)); |
| } |
| |
| // ---------------------- UserGroup methods ---------------------------------------------- |
| |
| @Override |
| public UserGroup createUserGroup(final UserGroup userGroup) { |
| verifyAuthorizerSupportsConfigurableUserGroups(); |
| authorizeTenantsAccess(RequestAction.WRITE); |
| validateCreationOfRevisableEntity(userGroup, USER_GROUP_ENTITY_TYPE); |
| validateIdentifierNotPresent(userGroup, USER_GROUP_ENTITY_TYPE); |
| |
| userGroup.setIdentifier(UUID.randomUUID().toString()); |
| return createRevisableEntity(userGroup, USER_GROUP_ENTITY_TYPE, currentUserIdentity(), |
| () -> authorizationService.createUserGroup(userGroup)); |
| } |
| |
| @Override |
| public List<UserGroup> getUserGroups() { |
| verifyAuthorizerIsManaged(); |
| authorizeTenantsAccess(RequestAction.READ); |
| return entityService.getEntities(() -> authorizationService.getUserGroups()); |
| } |
| |
| @Override |
| public UserGroup getUserGroup(final String identifier) { |
| verifyAuthorizerIsManaged(); |
| authorizeTenantsAccess(RequestAction.READ); |
| return entityService.get(() -> authorizationService.getUserGroup(identifier)); |
| } |
| |
| @Override |
| public UserGroup updateUserGroup(final UserGroup userGroup) { |
| verifyAuthorizerSupportsConfigurableUserGroups(); |
| authorizeTenantsAccess(RequestAction.WRITE); |
| validateUpdateOfRevisableEntity(userGroup, USER_GROUP_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| authorizationService.verifyUserGroupExists(userGroup.getIdentifier()); |
| |
| return updateRevisableEntity(userGroup, USER_GROUP_ENTITY_TYPE, currentUserIdentity(), |
| () -> authorizationService.updateUserGroup(userGroup)); |
| } |
| |
| @Override |
| public UserGroup deleteUserGroup(final String identifier, final RevisionInfo revisionInfo) { |
| verifyAuthorizerSupportsConfigurableUserGroups(); |
| authorizeTenantsAccess(RequestAction.DELETE); |
| validateDeleteOfRevisableEntity(identifier, revisionInfo, USER_GROUP_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| authorizationService.verifyUserGroupExists(identifier); |
| |
| return deleteRevisableEntity(identifier, USER_GROUP_ENTITY_TYPE, revisionInfo, |
| () -> authorizationService.deleteUserGroup(identifier)); |
| } |
| |
| // ---------------------- AccessPolicy methods ---------------------------------------------- |
| |
| @Override |
| public AccessPolicy createAccessPolicy(final AccessPolicy accessPolicy) { |
| verifyAuthorizerSupportsConfigurablePolicies(); |
| authorizePoliciesAccess(RequestAction.WRITE); |
| validateCreationOfRevisableEntity(accessPolicy, ACCESS_POLICY_ENTITY_TYPE); |
| validateIdentifierNotPresent(accessPolicy, ACCESS_POLICY_ENTITY_TYPE); |
| |
| accessPolicy.setIdentifier(UUID.randomUUID().toString()); |
| return createRevisableEntity(accessPolicy, ACCESS_POLICY_ENTITY_TYPE, currentUserIdentity(), |
| () -> authorizationService.createAccessPolicy(accessPolicy)); |
| } |
| |
| @Override |
| public AccessPolicy getAccessPolicy(final String identifier) { |
| verifyAuthorizerIsManaged(); |
| authorizePoliciesAccess(RequestAction.READ); |
| return entityService.get(() -> authorizationService.getAccessPolicy(identifier)); |
| } |
| |
| @Override |
| public AccessPolicy getAccessPolicy(final String resource, final RequestAction action) { |
| verifyAuthorizerIsManaged(); |
| authorizePoliciesAccess(RequestAction.READ); |
| return entityService.get(() -> authorizationService.getAccessPolicy(resource, action)); |
| } |
| |
| @Override |
| public List<AccessPolicy> getAccessPolicies() { |
| verifyAuthorizerIsManaged(); |
| authorizePoliciesAccess(RequestAction.READ); |
| return entityService.getEntities(() -> authorizationService.getAccessPolicies()); |
| } |
| |
| @Override |
| public AccessPolicy updateAccessPolicy(final AccessPolicy accessPolicy) { |
| verifyAuthorizerSupportsConfigurablePolicies(); |
| authorizePoliciesAccess(RequestAction.WRITE); |
| validateUpdateOfRevisableEntity(accessPolicy, ACCESS_POLICY_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| authorizationService.verifyAccessPolicyExists(accessPolicy.getIdentifier()); |
| |
| return updateRevisableEntity(accessPolicy, ACCESS_POLICY_ENTITY_TYPE, currentUserIdentity(), |
| () -> authorizationService.updateAccessPolicy(accessPolicy)); |
| } |
| |
| @Override |
| public AccessPolicy deleteAccessPolicy(final String identifier, final RevisionInfo revisionInfo) { |
| verifyAuthorizerSupportsConfigurablePolicies(); |
| authorizePoliciesAccess(RequestAction.DELETE); |
| validateDeleteOfRevisableEntity(identifier, revisionInfo, ACCESS_POLICY_ENTITY_TYPE); |
| |
| // verify outside of the revisable update so ResourceNotFoundException will be thrown instead of InvalidRevisionException |
| authorizationService.verifyAccessPolicyExists(identifier); |
| |
| return deleteRevisableEntity(identifier, ACCESS_POLICY_ENTITY_TYPE, revisionInfo, |
| () -> authorizationService.deleteAccessPolicy(identifier)); |
| } |
| |
| @Override |
| public List<Resource> getResources() { |
| authorizePoliciesAccess(RequestAction.READ); |
| return authorizationService.getResources(); |
| } |
| |
| // ---------------------- Permission methods ----------------------------- |
| |
| @Override |
| public CurrentUser getCurrentUser() { |
| return authorizationService.getCurrentUser(); |
| } |
| |
| |
| // ---------------------- Authorization methods ----------------------------- |
| |
| private void verifyAuthorizerIsManaged() { |
| authorizationService.verifyAuthorizerIsManaged(); |
| } |
| |
| private void verifyAuthorizerSupportsConfigurablePolicies() { |
| authorizationService.verifyAuthorizerSupportsConfigurablePolicies(); |
| } |
| |
| private void verifyAuthorizerSupportsConfigurableUserGroups() { |
| authorizationService.verifyAuthorizerSupportsConfigurableUserGroups(); |
| } |
| |
| // ---------------------- Configuration methods ----------------------------- |
| |
| @Override |
| public RegistryConfiguration getRegistryConfiguration() { |
| final RegistryConfiguration config = new RegistryConfiguration(); |
| |
| boolean hasAnyConfigurationAccess = false; |
| AccessDeniedException lastAccessDeniedException = null; |
| try { |
| final Authorizable policyAuthorizer = authorizableLookup.getPoliciesAuthorizable(); |
| authorizationService.authorize(policyAuthorizer, RequestAction.READ); |
| config.setSupportsManagedAuthorizer(authorizationService.isManagedAuthorizer()); |
| config.setSupportsConfigurableAuthorizer(authorizationService.isConfigurableAccessPolicyProvider()); |
| hasAnyConfigurationAccess = true; |
| } catch (AccessDeniedException e) { |
| lastAccessDeniedException = e; |
| } |
| |
| try { |
| authorizationService.authorize(authorizableLookup.getTenantsAuthorizable(), RequestAction.READ); |
| config.setSupportsConfigurableUsersAndGroups(authorizationService.isConfigurableUserGroupProvider()); |
| hasAnyConfigurationAccess = true; |
| } catch (AccessDeniedException e) { |
| lastAccessDeniedException = e; |
| } |
| |
| if (!hasAnyConfigurationAccess) { |
| // If the user doesn't have access to any configuration, then throw the exception. |
| // Otherwise, return what they can access. |
| throw lastAccessDeniedException; |
| } |
| |
| return config; |
| } |
| |
| // ---------------------- Helper methods ------------------------------------- |
| |
| private void authorizeBucketsAccess(RequestAction actionType) throws AccessDeniedException { |
| final Authorizable bucketsAuthorizable = authorizableLookup.getBucketsAuthorizable(); |
| authorizationService.authorize(bucketsAuthorizable, actionType); |
| } |
| |
| private void authorizeBucketAccess(final RequestAction actionType, final String bucketIdentifier) { |
| if (StringUtils.isBlank(bucketIdentifier)) { |
| throw new IllegalArgumentException("Unable to authorize access because bucket identifier is null or blank"); |
| } |
| |
| final Authorizable bucketAuthorizable = authorizableLookup.getBucketAuthorizable(bucketIdentifier); |
| authorizationService.authorize(bucketAuthorizable, actionType); |
| } |
| |
| private void authorizeBucketAccess(final RequestAction action, final Bundle bundle) { |
| // this should never happen, but if somehow the back-end didn't populate the bucket id let's make sure the bundle isn't returned |
| if (bundle == null) { |
| throw new IllegalStateException("Unable to authorize access because bucket identifier is null or blank"); |
| } |
| |
| authorizeBucketAccess(action, bundle.getBucketIdentifier()); |
| } |
| |
| private void authorizeBucketAccess(final RequestAction action, final VersionedFlow flow) { |
| // this should never happen, but if somehow the back-end didn't populate the bucket id let's make sure the flow isn't returned |
| if (flow == null) { |
| throw new IllegalStateException("Unable to authorize access because bucket identifier is null or blank"); |
| } |
| |
| authorizeBucketAccess(action, flow.getBucketIdentifier()); |
| } |
| |
| private void authorizeBucketAccess(final RequestAction action, final VersionedFlowSnapshot flowSnapshot) { |
| // this should never happen, but if somehow the back-end didn't populate the bucket id let's make sure the flow snapshot isn't returned |
| if (flowSnapshot == null || flowSnapshot.getSnapshotMetadata() == null) { |
| throw new IllegalStateException("Unable to authorize access because bucket identifier is null or blank"); |
| } |
| |
| authorizeBucketAccess(action, flowSnapshot.getSnapshotMetadata().getBucketIdentifier()); |
| } |
| |
| private void authorizeBucketAccess(final RequestAction action, final VersionedFlowSnapshotMetadata flowSnapshotMetadata) { |
| // this should never happen, but if somehow the back-end didn't populate the bucket id let's make sure the flow snapshot isn't returned |
| if (flowSnapshotMetadata == null) { |
| throw new IllegalStateException("Unable to authorize access because bucket identifier is null or blank"); |
| } |
| |
| authorizeBucketAccess(action, flowSnapshotMetadata.getBucketIdentifier()); |
| } |
| |
| private Set<String> getAuthorizedBucketIds(final RequestAction actionType) { |
| return authorizationService.getAuthorizedResources(actionType, ResourceType.Bucket) |
| .stream() |
| .map(StandardServiceFacade::extractBucketIdFromResource) |
| .filter(Objects::nonNull) |
| .distinct() |
| .collect(Collectors.toSet()); |
| } |
| |
| private static String extractBucketIdFromResource(Resource resource) { |
| if (resource == null || resource.getIdentifier() == null || !resource.getIdentifier().startsWith("/buckets/")) { |
| return null; |
| } |
| |
| final String[] pathComponents = resource.getIdentifier().split("/"); |
| if (pathComponents.length < 3) { |
| return null; |
| } |
| return pathComponents[2]; |
| } |
| |
| private String generateResourceUri(final URI baseUri, final String... path) { |
| final URI fullUri = UriBuilder.fromUri(baseUri).segment(path).build(); |
| return fullUri.toString(); |
| } |
| |
| private void authorizePoliciesAccess(final RequestAction actionType) { |
| final Authorizable policiesAuthorizable = authorizableLookup.getPoliciesAuthorizable(); |
| authorizationService.authorize(policiesAuthorizable, actionType); |
| } |
| |
| private void authorizeTenantsAccess(RequestAction actionType) { |
| final Authorizable tenantsAuthorizable = authorizableLookup.getTenantsAuthorizable(); |
| authorizationService.authorize(tenantsAuthorizable, actionType); |
| } |
| |
| // ---------------------- Revision Helper Methods ------------------------------------- |
| |
| private void validateCreationOfRevisableEntity(final RevisableEntity entity, final String entityTypeName) { |
| if (entity == null) { |
| throw new IllegalArgumentException(entityTypeName + " cannot be null"); |
| } |
| |
| // skip checking revision if feature is disabled |
| if (!revisionFeature.isEnabled()) { |
| return; |
| } |
| |
| // NOT: restore identifier check here when we no longer needs backwards compatibility |
| |
| if (entity.getRevision() == null |
| || entity.getRevision().getVersion() == null |
| || entity.getRevision().getVersion().longValue() != 0) { |
| throw new IllegalArgumentException("A revision of 0 must be specified when creating a new " + entityTypeName + "."); |
| } |
| } |
| |
| /** |
| * NOTE: This logic should be moved back to validateCreationOfRevisableEntity once we no longer need to maintain |
| * backwards compatibility (i.e. on a major release like 1.0.0). |
| * |
| * Currently NiFi has been sending an identifier when creating a flow, so we need to continue to allow that. |
| */ |
| private void validateIdentifierNotPresent(final RevisableEntity entity, final String entityTypeName) { |
| if (entity.getIdentifier() != null) { |
| throw new IllegalArgumentException(entityTypeName + " identifier cannot be specified when creating a new " |
| + entityTypeName.toLowerCase() + "."); |
| } |
| } |
| |
| private void validateUpdateOfRevisableEntity(final RevisableEntity entity, final String entityTypeName) { |
| if (entity == null) { |
| throw new IllegalArgumentException(entityTypeName + " cannot be null"); |
| } |
| |
| // skip checking revision if feature is disabled |
| if (!revisionFeature.isEnabled()) { |
| return; |
| } |
| |
| if (entity.getRevision() == null || entity.getRevision().getVersion() == null) { |
| throw new IllegalArgumentException("Revision info must be specified."); |
| } |
| } |
| |
| private void validateDeleteOfRevisableEntity(final String identifier, final RevisionInfo revision, final String entityTypeName) { |
| if (identifier == null || identifier.trim().isEmpty()) { |
| throw new IllegalArgumentException(entityTypeName + " identifier is required"); |
| } |
| |
| // skip checking revision if feature is disabled |
| if (!revisionFeature.isEnabled()) { |
| return; |
| } |
| |
| if (revision == null || revision.getVersion() == null) { |
| throw new IllegalArgumentException("Revision info must be specified."); |
| } |
| } |
| |
| private <T extends RevisableEntity> T createRevisableEntity(final T requestEntity, final String entityTypeName, |
| final String creatorIdentity, final Supplier<T> createEntity) { |
| |
| // skip using the entity service if revision feature is disabled |
| if (!revisionFeature.isEnabled()) { |
| return createEntity.get(); |
| } else { |
| try { |
| return entityService.create(requestEntity, creatorIdentity, createEntity); |
| } catch (InvalidRevisionException e) { |
| final String msg = String.format(INVALID_REVISION_MSG, entityTypeName, "create", requestEntity.getIdentifier()); |
| throw new InvalidRevisionException(msg, e); |
| } |
| } |
| } |
| |
| private <T extends RevisableEntity> T updateRevisableEntity(final T requestEntity, final String entityTypeName, |
| final String updaterIdentity, final Supplier<T> updateEntity) { |
| |
| // skip using the entity service if revision feature is disabled |
| if (!revisionFeature.isEnabled()) { |
| return updateEntity.get(); |
| } else { |
| try { |
| return entityService.update(requestEntity, updaterIdentity, updateEntity); |
| } catch (InvalidRevisionException e) { |
| final String msg = String.format(INVALID_REVISION_MSG, entityTypeName, "update", requestEntity.getIdentifier()); |
| throw new InvalidRevisionException(msg, e); |
| } |
| } |
| } |
| |
| private <T extends RevisableEntity> T deleteRevisableEntity(final String entityIdentifier, final String entityTypeName, |
| final RevisionInfo revisionInfo, final Supplier<T> deleteEntity) { |
| // skip using the entity service if revision feature is disabled |
| if (!revisionFeature.isEnabled()) { |
| return deleteEntity.get(); |
| } else { |
| try { |
| return entityService.delete(entityIdentifier, revisionInfo, deleteEntity); |
| } catch (InvalidRevisionException e) { |
| final String msg = String.format(INVALID_REVISION_MSG, entityTypeName, "delete", entityIdentifier); |
| throw new InvalidRevisionException(msg, e); |
| } |
| } |
| } |
| |
| } |