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

🐛 [Service Config] Fixed returned exception when forbidden change is detected #4199

Merged
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,47 @@
/*******************************************************************************
* Copyright (c) 2025, 2025 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Eurotech - initial API and implementation
*******************************************************************************/
package org.eclipse.kapua.commons.rest.errors;

import org.eclipse.kapua.commons.configuration.exception.ServiceConfigurationForbiddenException;
import org.eclipse.kapua.commons.rest.model.errors.ServiceConfigurationUpdateForbiddenExceptionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class ServiceConfigurationUpdateForbiddenExceptionMapper implements ExceptionMapper<ServiceConfigurationForbiddenException> {

private static final Logger LOG = LoggerFactory.getLogger(ServiceConfigurationUpdateForbiddenExceptionMapper.class);

private final boolean showStackTrace;

@Inject
public ServiceConfigurationUpdateForbiddenExceptionMapper(ExceptionConfigurationProvider exceptionConfigurationProvider) {
this.showStackTrace = exceptionConfigurationProvider.showStackTrace();
}

@Override
public Response toResponse(ServiceConfigurationForbiddenException serviceConfigurationForbiddenException) {
LOG.error(serviceConfigurationForbiddenException.getMessage(), serviceConfigurationForbiddenException);

return Response
.status(Status.FORBIDDEN)
.entity(new ServiceConfigurationUpdateForbiddenExceptionInfo(serviceConfigurationForbiddenException, showStackTrace))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2025, 2025 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Eurotech - initial API and implementation
*******************************************************************************/
package org.eclipse.kapua.commons.rest.model.errors;

import org.eclipse.kapua.commons.configuration.exception.ServiceConfigurationForbiddenException;
import org.eclipse.kapua.model.config.metatype.KapuaTad;
import org.eclipse.kapua.model.id.KapuaId;
import org.eclipse.kapua.model.id.KapuaIdAdapter;
import org.eclipse.kapua.service.config.KapuaConfigurableService;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement(name = "serviceConfigurationUpdateForbiddenExceptionInfo")
@XmlAccessorType(XmlAccessType.FIELD)
public class ServiceConfigurationUpdateForbiddenExceptionInfo extends ExceptionInfo {

@XmlElement(name = "scopeId")
@XmlJavaTypeAdapter(KapuaIdAdapter.class)
private KapuaId scopeId;

@XmlElement(name = "servicePid")
private String servicePid;

@XmlElement(name = "propertyId")
private String propertyId;

@XmlElement(name = "propertyValue")
private String propertyValue;

/**
* Constructor.
*
* @since 2.1.0
*/
protected ServiceConfigurationUpdateForbiddenExceptionInfo() {
super();
}

/**
* Constructor.
*
* @param serviceConfigurationForbiddenException The original exception.
* @since 2.1.0
*/
public ServiceConfigurationUpdateForbiddenExceptionInfo(ServiceConfigurationForbiddenException serviceConfigurationForbiddenException, boolean showStackTrace) {
super(403/*Response.Status.FORBIDDEN*/, serviceConfigurationForbiddenException, showStackTrace);

this.servicePid = serviceConfigurationForbiddenException.getServicePid();
this.scopeId = serviceConfigurationForbiddenException.getScopeId();
this.propertyId = serviceConfigurationForbiddenException.getPropertyId();
this.propertyValue = serviceConfigurationForbiddenException.getPropertyValue();
}

/**
* Gets the scope {@link KapuaId} for which the update is forbidden.
*
* @return The scope {@link KapuaId} for which the update is forbidden.
* @since 2.1.0
*/
public KapuaId getScopeId() {
return scopeId;
}

/**
* Gets the {@link KapuaConfigurableService} pid.
*
* @return he {@link KapuaConfigurableService} pid.
* @since 2.1.0
*/
public String getServicePid() {
return servicePid;
}

/**
* Gets the {@link KapuaTad#getId()} for which the update is forbidden.
*
* @return The {@link KapuaTad#getId()} for which the update is forbidden.
* @since 2.1.0
*/
public String getPropertyId() {
return propertyId;
}

/**
* Gets the {@link KapuaTad} value for which the update is forbidden.
*
* @return The {@link KapuaTad} value for which the update is forbidden.
* @since 2.1.0
*/
public String getPropertyValue() {
return propertyValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.kapua.KapuaException;
import org.eclipse.kapua.KapuaIllegalArgumentException;
import org.eclipse.kapua.KapuaIllegalNullArgumentException;
import org.eclipse.kapua.commons.configuration.exception.ServiceConfigurationForbiddenException;
import org.eclipse.kapua.commons.security.KapuaSecurityUtils;
import org.eclipse.kapua.commons.util.ArgumentValidator;
import org.eclipse.kapua.commons.util.StringUtil;
Expand Down Expand Up @@ -154,7 +155,7 @@ public void setConfigValues(KapuaId scopeId, Optional<KapuaId> parentId, Map<Str

if (preventChange) {
// ... prevent the change!
throw KapuaException.internalError(String.format("The configuration \"%s\" cannot be changed by this user in this account", ad.getId()));
throw new ServiceConfigurationForbiddenException(scopeId, pid, ad.getId(), String.valueOf(values.get(ad.getId())));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,10 @@ public enum KapuaConfigurationErrorCodes implements KapuaErrorCode {
* @since 2.0.0
*/
PARENT_LIMIT_EXCEEDED_BY,

/**
* @see ServiceConfigurationForbiddenException
* @since 2.1.0
*/
UPDATE_PROPERTY_FORBIDDEN,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*******************************************************************************
* Copyright (c) 2025, 2025 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Eurotech - initial API and implementation
*******************************************************************************/
package org.eclipse.kapua.commons.configuration.exception;

import org.eclipse.kapua.model.config.metatype.KapuaTad;
import org.eclipse.kapua.model.id.KapuaId;
import org.eclipse.kapua.service.account.Account;
import org.eclipse.kapua.service.config.KapuaConfigurableService;
import org.eclipse.kapua.service.config.ServiceComponentConfiguration;
import org.eclipse.kapua.service.user.User;

/**
* {@link KapuaConfigurationException} to {@code throw} when an update of a {@link ServiceComponentConfiguration#getProperties()} contains updates to values that cannot be updated by the curren {@link User}.
* <p>
* {@link ServiceComponentConfiguration#getProperties()} can be updated under the following conditions:
* <ul>
* <li>If the current {@link User} is root. Root {@link User} can do whatever he wants</li>
* <li>If the {@link KapuaTad} is marked to allow self-edit. For those properties a {@link User} can update the values for its {@link Account}</li>
* <li>If the {@link ServiceComponentConfiguration} belongs to a child {@link Account} of the current {@link User}</li>
* </ul>
*
* @since 2.1.0
*/
public class ServiceConfigurationForbiddenException extends KapuaConfigurationException {

private final KapuaId scopeId;
private final String servicePid;

private final String propertyId;

private final String propertyValue;

/**
* Constructor.
*
* @param servicePid The {@link KapuaConfigurableService} pid.
* @param scopeId The scope {@link KapuaId} for which limit has been exceeded.
* @param propertyId The {@link KapuaTad#getId()} for which the update is forbidden.
* @param propertyValue The {@link KapuaTad} value for which the update is forbidden.
* @since 2.0.0
*/
public ServiceConfigurationForbiddenException(KapuaId scopeId, String servicePid, String propertyId, String propertyValue) {
super(KapuaConfigurationErrorCodes.UPDATE_PROPERTY_FORBIDDEN, scopeId, servicePid, propertyId, propertyValue);

this.scopeId = scopeId;
this.servicePid = servicePid;
this.propertyId = propertyId;
this.propertyValue = propertyValue;
}

/**
* Gets the scope {@link KapuaId} for which the update is forbidden.
*
* @return The scope {@link KapuaId} for which the update is forbidden.
* @since 2.1.0
*/
public KapuaId getScopeId() {
return scopeId;
}

/**
* Gets the {@link KapuaConfigurableService} pid for which the update is forbidden.
*
* @return he {@link KapuaConfigurableService} pid for which the update is forbidden.
* @since 2.1.0
*/
public String getServicePid() {
return servicePid;
}

/**
* Gets the {@link KapuaTad#getId()} for which the update is forbidden.
*
* @return The {@link KapuaTad#getId()} for which the update is forbidden.
* @since 2.1.0
*/
public String getPropertyId() {
return propertyId;
}

/**
* Gets the {@link KapuaTad} value for which the update is forbidden.
*
* @return The {@link KapuaTad} value for which the update is forbidden.
* @since 2.1.0
*/
public String getPropertyValue() {
return propertyValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ LIMIT_EXCEEDED=The maximum of resources for the {0} service for the account {1}
LIMIT_EXCEEDED_BY=The maximum of resources for the {0} service for the account {1} has been exceeded. The resource limit is exceeded by {2}.
PARENT_LIMIT_EXCEEDED=The maximum of resources for the {0} service for the parent account {1} has been exceeded.
PARENT_LIMIT_EXCEEDED_BY=The maximum of resources for the {0} service for the parent account {1} has been exceeded. The resource limit is exceeded by {2}.
UPDATE_PROPERTY_FORBIDDEN=Current User cannot update property {2} of ServiceComponentConfiguration {1} of Account {0} with value {3}
2 changes: 2 additions & 0 deletions rest-api/resources/src/main/resources/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,8 @@ components:
$ref: './serviceConfiguration/serviceConfiguration.yaml#/components/schemas/option'
serviceAttributeDefinition:
$ref: './serviceConfiguration/serviceConfiguration.yaml#/components/schemas/attributeDefinition'
serviceConfigurationUpdateForbiddenExceptionInfo:
$ref: './serviceConfiguration/serviceConfiguration.yaml#/components/schemas/serviceConfigurationUpdateForbiddenExceptionInfo'
### System Info Entities ###
systemInfo:
$ref: './systemInfo/systemInfo.yaml#/components/schemas/systemInfo'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,20 @@ paths:
401:
$ref: '../openapi.yaml#/components/responses/unauthenticated'
403:
$ref: '../openapi.yaml#/components/responses/subjectUnauthorized'
description: The requested update is forbidden
content:
application/json:
schema:
oneOf:
- $ref: '../openapi.yaml#/components/schemas/subjectUnauthorizedExceptionInfo'
- $ref: './serviceConfiguration.yaml#/components/schemas/serviceConfigurationUpdateForbiddenExceptionInfo'
application/xml:
schema:
oneOf:
- $ref: '../openapi.yaml#/components/schemas/subjectUnauthorizedExceptionInfo'
- $ref: './serviceConfiguration.yaml#/components/schemas/serviceConfigurationUpdateForbiddenExceptionInfo'
xml:
name: 'serviceConfigurationUpdateForbiddenExceptionInfo'
404:
$ref: '../openapi.yaml#/components/responses/entityNotFound'
500:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,20 @@ paths:
401:
$ref: '../openapi.yaml#/components/responses/unauthenticated'
403:
$ref: '../openapi.yaml#/components/responses/subjectUnauthorized'
description: The requested update is forbidden
content:
application/json:
schema:
oneOf:
- $ref: '../openapi.yaml#/components/schemas/subjectUnauthorizedExceptionInfo'
- $ref: './serviceConfiguration.yaml#/components/schemas/serviceConfigurationUpdateForbiddenExceptionInfo'
application/xml:
schema:
oneOf:
- $ref: '../openapi.yaml#/components/schemas/subjectUnauthorizedExceptionInfo'
- $ref: './serviceConfiguration.yaml#/components/schemas/serviceConfigurationUpdateForbiddenExceptionInfo'
xml:
name: 'serviceConfigurationUpdateForbiddenExceptionInfo'
404:
$ref: '../openapi.yaml#/components/responses/entityNotFound'
500:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,30 @@ components:
size:
type: integer

### Exception Info
serviceConfigurationUpdateForbiddenExceptionInfo:
description: The update of the configuration for the service contains an update to a property than cannot be updated
allOf:
- $ref: '../openapi.yaml#/components/schemas/exceptionInfo'
- properties:
scopeId:
description: The scope for which the update is forbidden
$ref: '../openapi.yaml#/components/schemas/kapuaId'
servicePid:
type: string
description: The Pid of the service
propertyId:
type: string
description: The property id for which the update is forbidden.
propertyValue:
type: string
description: The property value for which the update is forbidden.
example:
type: "serviceConfigurationUpdateForbiddenExceptionInfo"
httpErrorCode: 403
message: "Current User cannot update property maxNumberChildEntities of ServiceComponentConfiguration org.eclipse.kapua.service.account.AccountService of Account 2 with value 10"
kapuaErrorCode: "UPDATE_PROPERTY_FORBIDDEN"
scopeId: 2
servicePid: "org.eclipse.kapua.service.account.AccountService"
propertyId: "maxNumberChildEntities"
propertyValue: "10"