Skip to content
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
@@ -0,0 +1,71 @@
package uk.co.compendiumdev.thingifier.adapter.http.apihandlers;

import java.util.Optional;
import uk.co.compendiumdev.thingifier.api.http.ThingifierRequestContext;
import uk.co.compendiumdev.thingifier.api.response.ApiResponse;
import uk.co.compendiumdev.thingifier.api.security.DataScopeCreationPolicy;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiDataScopeSelection;
import uk.co.compendiumdev.thingifier.core.repository.ThingStore;

/**
* Applies trusted data-scope selections to the shared request context.
*
* <p>Route auth and scoped sessions both use this so their scope-switching rules stay identical.
* The selection is trusted because caller code only passes decisions returned by an authenticator
* or scoped-session resolver.
*/
final class DataScopeSelectionApplier {

private final ThingifierApiRuntime runtime;

DataScopeSelectionApplier(final ThingifierApiRuntime runtime) {
this.runtime = runtime;
}

/**
* Switches the request context to the selected data scope.
*
* @param context active request context to update
* @param selection trusted data-scope selection
* @return error response when the selected scope cannot be resolved, otherwise null
*/
ApiResponse apply(
final ThingifierRequestContext context,
final ThingifierApiDataScopeSelection selection) {
if (selection == null) {
return null;
}

if (requiresPreExistingScope(context, selection)) {
return ApiResponse.error404("Could not find data scope " + selection.dataScopeName());
}

final Optional<ThingStore> selectedStore =
runtime.storeForDataScope(selection.dataScopeName(), selection.creationPolicy());
if (selectedStore.isEmpty()) {
return ApiResponse.error404("Could not find data scope " + selection.dataScopeName());
}

if (requiresEmptyScopeAfterHeaderCreation(context, selection)) {
selectedStore.get().administration().clearAllData();
}
context.useDataScope(selection.dataScopeName(), selectedStore.get());
return null;
}

private boolean requiresPreExistingScope(
final ThingifierRequestContext context,
final ThingifierApiDataScopeSelection selection) {
return selection.creationPolicy() == DataScopeCreationPolicy.USE_EXISTING_ONLY
&& selection.dataScopeName().equals(context.dataScopeName())
&& context.wasDataScopeCreatedWhenContextCreated();
}

private boolean requiresEmptyScopeAfterHeaderCreation(
final ThingifierRequestContext context,
final ThingifierApiDataScopeSelection selection) {
return selection.creationPolicy() == DataScopeCreationPolicy.ENSURE_EXISTS
&& selection.dataScopeName().equals(context.dataScopeName())
&& context.wasDataScopeCreatedWhenContextCreated();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,19 @@
import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.BasicAuthHeaderParser;
import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.BearerAuthHeaderParser;
import uk.co.compendiumdev.thingifier.api.response.ApiResponse;
import uk.co.compendiumdev.thingifier.api.security.DataScopeCreationPolicy;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiAuthenticationContext;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiAuthenticationResult;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiAuthenticator;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiAuthorizationContext;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiAuthorizationResult;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiAuthorizer;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiDataScopeSelection;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiRouteAuthDetails;
import uk.co.compendiumdev.thingifier.api.security.ThingifierApiSecuritySchemeType;
import uk.co.compendiumdev.thingifier.api.spec.ApiRoutePathMatcher;
import uk.co.compendiumdev.thingifier.api.spec.ThingifierApiRouteRule;
import uk.co.compendiumdev.thingifier.application.schema.EntityTypeRef;
import uk.co.compendiumdev.thingifier.application.schema.RelationshipSpec;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.repository.ThingStore;

/**
* Enforces route-level authentication and authorization configured in the API spec.
Expand Down Expand Up @@ -384,39 +381,8 @@ private ApiResponse applyDataScopeSelection(
if (authentication.dataScopeSelection().isEmpty()) {
return null;
}

final ThingifierApiDataScopeSelection selection = authentication.dataScopeSelection().get();
if (requiresPreExistingScope(context, selection)) {
return ApiResponse.error404("Could not find data scope " + selection.dataScopeName());
}

final Optional<ThingStore> selectedStore =
runtime.storeForDataScope(selection.dataScopeName(), selection.creationPolicy());
if (selectedStore.isEmpty()) {
return ApiResponse.error404("Could not find data scope " + selection.dataScopeName());
}

if (requiresEmptyScopeAfterHeaderCreation(context, selection)) {
selectedStore.get().administration().clearAllData();
}
context.useDataScope(selection.dataScopeName(), selectedStore.get());
return null;
}

private boolean requiresPreExistingScope(
final ThingifierRequestContext context,
final ThingifierApiDataScopeSelection selection) {
return selection.creationPolicy() == DataScopeCreationPolicy.USE_EXISTING_ONLY
&& selection.dataScopeName().equals(context.dataScopeName())
&& context.wasDataScopeCreatedWhenContextCreated();
}

private boolean requiresEmptyScopeAfterHeaderCreation(
final ThingifierRequestContext context,
final ThingifierApiDataScopeSelection selection) {
return selection.creationPolicy() == DataScopeCreationPolicy.ENSURE_EXISTS
&& selection.dataScopeName().equals(context.dataScopeName())
&& context.wasDataScopeCreatedWhenContextCreated();
return new DataScopeSelectionApplier(runtime)
.apply(context, authentication.dataScopeSelection().get());
}

/**
Expand Down
Loading
Loading