This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 5f59091b70 FINERACT-2283: Self-service APIs are disabled by default
5f59091b70 is described below

commit 5f59091b7057cfe08262122fe56f57cb66b10ec6
Author: Adam Saghy <[email protected]>
AuthorDate: Fri May 16 20:44:49 2025 +0200

    FINERACT-2283: Self-service APIs are disabled by default
---
 .../core/config/FineractProperties.java            |  7 ++++
 .../sms/serialization/SmsCampaignValidator.java    |  4 +-
 .../core/config/OAuth2SecurityConfig.java          | 23 +++++++++---
 .../infrastructure/core/config/SecurityConfig.java | 24 +++++++++---
 .../gcm/service/NotificationSenderService.java     |  4 +-
 .../vote/SelfServiceUserAuthorizationManager.java  |  2 +-
 .../api/SelfAccountTransferApiResource.java        |  3 ++
 .../api/SelfBeneficiariesTPTApiResource.java       |  3 ++
 .../self/client/api/SelfClientsApiResource.java    |  3 ++
 .../SelfServiceModuleIsEnabledCondition.java}      | 14 +++----
 .../portfolio/self/config/SelfServiceWarning.java  | 43 ++++++++++++++++++++++
 .../api/DeviceRegistrationApiConstants.java        |  2 +-
 .../device}/api/DeviceRegistrationApiResource.java | 13 ++++---
 .../self/device}/domain/DeviceRegistration.java    |  2 +-
 .../device}/domain/DeviceRegistrationData.java     |  2 +-
 .../domain/DeviceRegistrationRepository.java       |  2 +-
 .../DeviceRegistrationRepositoryWrapper.java       |  4 +-
 .../DeviceRegistrationNotFoundException.java       |  2 +-
 .../DeviceRegistrationReadPlatformService.java     |  4 +-
 .../DeviceRegistrationReadPlatformServiceImpl.java |  6 +--
 .../DeviceRegistrationWritePlatformService.java    |  4 +-
 ...DeviceRegistrationWritePlatformServiceImpl.java |  6 +--
 .../self/loanaccount/api/SelfLoansApiResource.java |  3 ++
 .../self/pockets/api/PocketApiResource.java        |  3 ++
 .../products/api/SelfLoanProductsApiResource.java  |  3 ++
 .../api/SelfSavingsProductsApiResource.java        |  3 ++
 .../products/api/SelfShareProductsApiResource.java |  3 ++
 .../api/SelfServiceRegistrationApiResource.java    |  3 ++
 .../self/runreport/SelfRunReportApiResource.java   |  3 ++
 .../self/savings/api/SelfSavingsApiResource.java   |  3 ++
 .../api/SelfAuthenticationApiResource.java         |  3 ++
 .../self/security/api/SelfUserApiResource.java     |  3 ++
 .../security/api/SelfUserDetailsApiResource.java   |  3 ++
 .../api/SelfShareAccountsApiResource.java          |  3 ++
 .../self/spm/api/SelfScorecardApiResource.java     |  3 ++
 .../portfolio/self/spm/api/SelfSpmApiResource.java |  3 ++
 .../src/main/resources/application.properties      |  2 +
 .../src/test/resources/application-test.properties |  1 +
 .../SavingsAccountsExternalIdTest.java             |  2 +-
 39 files changed, 178 insertions(+), 46 deletions(-)

diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
index ed4064aa0a..d6aa63b324 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
@@ -548,6 +548,7 @@ public class FineractProperties {
     public static class FineractModulesProperties {
 
         private FineractInvestorModuleProperties investor;
+        private FineractSelfServiceModuleProperties selfService;
     }
 
     @Getter
@@ -556,6 +557,12 @@ public class FineractProperties {
 
     }
 
+    @Getter
+    @Setter
+    public static class FineractSelfServiceModuleProperties extends 
AbstractFineractModuleProperties {
+
+    }
+
     @Getter
     @Setter
     public static class FineractSqlValidationProperties {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
index 0861a68fee..8dd9c077aa 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
@@ -36,10 +36,10 @@ import 
org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
-import 
org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationRepositoryWrapper;
 import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
 import org.apache.fineract.portfolio.client.domain.Client;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistration;
+import 
org.apache.fineract.portfolio.self.device.domain.DeviceRegistrationRepositoryWrapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
index e20ba55560..0b7346c28a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
@@ -25,7 +25,9 @@ import static 
org.springframework.security.authorization.AuthorityAuthorizationM
 import static 
org.springframework.security.authorization.AuthorizationManagers.allOf;
 import static 
org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import 
org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
 import 
org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService;
 import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -47,8 +49,10 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.http.HttpMethod;
+import org.springframework.security.authorization.AuthorizationManager;
 import 
org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import 
org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -61,6 +65,7 @@ import 
org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.security.oauth2.jwt.Jwt;
 import 
org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
 import org.springframework.security.web.SecurityFilterChain;
+import 
org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 import 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 import org.springframework.security.web.context.SecurityContextHolderFilter;
 
@@ -101,17 +106,25 @@ public class OAuth2SecurityConfig {
     public SecurityFilterChain filterChain(HttpSecurity http) throws Exception 
{
         http //
                 
.securityMatcher(antMatcher("/api/**")).authorizeHttpRequests((auth) -> {
+                    List<AuthorizationManager<RequestAuthorizationContext>> 
authorizationManagers = new ArrayList<>();
+                    authorizationManagers.add(fullyAuthenticated());
+                    
authorizationManagers.add(hasAuthority("TWOFACTOR_AUTHENTICATED"));
+                    if 
(fineractProperties.getModule().getSelfService().isEnabled()) {
+                        auth.requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/authentication")).permitAll() //
+                                .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration")).permitAll() //
+                                .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration/user")).permitAll(); //
+                        
authorizationManagers.add(selfServiceUserAuthManager());
+                    }
+
                     auth.requestMatchers(antMatcher(HttpMethod.OPTIONS, 
"/api/**")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/echo")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/authentication")).permitAll() //
-                            .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/authentication")).permitAll() //
-                            .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration")).permitAll() //
-                            .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration/user")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/twofactor/validate")).fullyAuthenticated() //
                             
.requestMatchers(antMatcher("/api/*/twofactor")).fullyAuthenticated() //
                             .requestMatchers(antMatcher("/api/**"))
-                            .access(allOf(fullyAuthenticated(), 
hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
-                }).csrf((csrf) -> csrf.disable()) // NOSONAR only creating a 
service that is used by non-browser clients
+                            .access(allOf(authorizationManagers.toArray(new 
AuthorizationManager[0]))); //
+                }).csrf(AbstractHttpConfigurer::disable) // NOSONAR only 
creating a service that is used by non-browser
+                                                         // clients
                 .exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new 
OAuth2ExceptionEntryPoint()))
                 .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> 
jwt.jwtAuthenticationConverter(authenticationConverter()))
                         .authenticationEntryPoint(new 
OAuth2ExceptionEntryPoint())) //
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
index 2aa96f7e5f..92e0a068f8 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
@@ -19,11 +19,13 @@
 
 package org.apache.fineract.infrastructure.core.config;
 
+import static 
org.apache.fineract.infrastructure.security.vote.SelfServiceUserAuthorizationManager.selfServiceUserAuthManager;
 import static 
org.springframework.security.authorization.AuthenticatedAuthorizationManager.fullyAuthenticated;
 import static 
org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
 import static 
org.springframework.security.authorization.AuthorizationManagers.allOf;
 import static 
org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import org.apache.fineract.commands.domain.CommandSourceRepository;
@@ -60,14 +62,17 @@ import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.ProviderManager;
 import 
org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.config.Customizer;
 import 
org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import 
org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import 
org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.access.ExceptionTranslationFilter;
+import 
org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 import 
org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
 import org.springframework.security.web.context.SecurityContextHolderFilter;
 import org.springframework.web.cors.CorsConfiguration;
@@ -123,20 +128,27 @@ public class SecurityConfig {
     public SecurityFilterChain filterChain(HttpSecurity http) throws Exception 
{
         http //
                 
.securityMatcher(antMatcher("/api/**")).authorizeHttpRequests((auth) -> {
+                    List<AuthorizationManager<RequestAuthorizationContext>> 
authorizationManagers = new ArrayList<>();
+                    authorizationManagers.add(fullyAuthenticated());
+                    
authorizationManagers.add(hasAuthority("TWOFACTOR_AUTHENTICATED"));
+                    if 
(fineractProperties.getModule().getSelfService().isEnabled()) {
+                        auth.requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/authentication")).permitAll() //
+                                .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration")).permitAll() //
+                                .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration/user")).permitAll(); //
+                        
authorizationManagers.add(selfServiceUserAuthManager());
+                    }
                     auth.requestMatchers(antMatcher(HttpMethod.OPTIONS, 
"/api/**")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/echo")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/authentication")).permitAll() //
-                            .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/authentication")).permitAll() //
-                            .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration")).permitAll() //
-                            .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/self/registration/user")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.PUT, 
"/api/*/instance-mode")).permitAll() //
                             .requestMatchers(antMatcher(HttpMethod.POST, 
"/api/*/twofactor/validate")).fullyAuthenticated() //
                             
.requestMatchers(antMatcher("/api/*/twofactor")).fullyAuthenticated() //
                             .requestMatchers(antMatcher("/api/**"))
-                            .access(allOf(fullyAuthenticated(), 
hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
+                            .access(allOf(authorizationManagers.toArray(new 
AuthorizationManager[0]))); //
                 }).httpBasic((httpBasic) -> 
httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())) //
-                .cors(Customizer.withDefaults()).csrf((csrf) -> 
csrf.disable()) // NOSONAR only creating a service that
-                                                                               
 // is used by non-browser clients
+                
.cors(Customizer.withDefaults()).csrf(AbstractHttpConfigurer::disable) // 
NOSONAR only creating a
+                                                                               
        // service that
+                // is used by non-browser clients
                 .sessionManagement((smc) -> 
smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
                 .addFilterBefore(tenantAwareBasicAuthenticationFilter(), 
SecurityContextHolderFilter.class) //
                 .addFilterAfter(requestResponseFilter(), 
ExceptionTranslationFilter.class) //
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/NotificationSenderService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/NotificationSenderService.java
index 53eb36764f..39a8a340c0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/NotificationSenderService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/NotificationSenderService.java
@@ -27,8 +27,6 @@ import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.configuration.service.ExternalServicesPropertiesReadPlatformService;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.gcm.GcmConstants;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
-import 
org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationRepositoryWrapper;
 import org.apache.fineract.infrastructure.gcm.domain.Message;
 import org.apache.fineract.infrastructure.gcm.domain.Message.Priority;
 import org.apache.fineract.infrastructure.gcm.domain.Notification;
@@ -38,6 +36,8 @@ import org.apache.fineract.infrastructure.gcm.domain.Sender;
 import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
 import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
 import org.apache.fineract.infrastructure.sms.domain.SmsMessageStatusType;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistration;
+import 
org.apache.fineract.portfolio.self.device.domain.DeviceRegistrationRepositoryWrapper;
 import org.springframework.stereotype.Service;
 
 @Service
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/vote/SelfServiceUserAuthorizationManager.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/vote/SelfServiceUserAuthorizationManager.java
index 0bb9197267..1b40ed45d1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/vote/SelfServiceUserAuthorizationManager.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/vote/SelfServiceUserAuthorizationManager.java
@@ -33,7 +33,7 @@ public class SelfServiceUserAuthorizationManager implements 
AuthorizationManager
             AppUser user = (AppUser) authentication.get().getPrincipal();
 
             String pathURL = fi.getRequest().getRequestURL().toString();
-            boolean isSelfServiceRequest = (pathURL != null && 
pathURL.contains("/self/"));
+            boolean isSelfServiceRequest = pathURL.contains("/self/");
 
             boolean notAllowed = ((isSelfServiceRequest && 
!user.isSelfServiceUser())
                     || (!isSelfServiceRequest && user.isSelfServiceUser()));
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfAccountTransferApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfAccountTransferApiResource.java
index 963f87b6da..c2712a1ab1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfAccountTransferApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfAccountTransferApiResource.java
@@ -57,13 +57,16 @@ import 
org.apache.fineract.portfolio.self.account.exception.BeneficiaryTransferL
 import 
org.apache.fineract.portfolio.self.account.exception.DailyTPTTransactionAmountLimitExceededException;
 import 
org.apache.fineract.portfolio.self.account.service.SelfAccountTransferReadService;
 import 
org.apache.fineract.portfolio.self.account.service.SelfBeneficiariesTPTReadPlatformService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/accounttransfers")
 @Component
 @Tag(name = "Self Account transfer", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfAccountTransferApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfBeneficiariesTPTApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfBeneficiariesTPTApiResource.java
index 8833e34aba..ba2067ebdd 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfBeneficiariesTPTApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/account/api/SelfBeneficiariesTPTApiResource.java
@@ -56,12 +56,15 @@ import 
org.apache.fineract.portfolio.account.PortfolioAccountType;
 import 
org.apache.fineract.portfolio.account.service.AccountTransferEnumerations;
 import 
org.apache.fineract.portfolio.self.account.data.SelfBeneficiariesTPTData;
 import 
org.apache.fineract.portfolio.self.account.service.SelfBeneficiariesTPTReadPlatformService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/beneficiaries/tpt")
 @Component
 @Tag(name = "Self Third Party Transfer", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfBeneficiariesTPTApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/client/api/SelfClientsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/client/api/SelfClientsApiResource.java
index f149a8c84e..4897cd22c4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/client/api/SelfClientsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/client/api/SelfClientsApiResource.java
@@ -53,16 +53,19 @@ import 
org.apache.fineract.portfolio.client.api.ClientsApiResource;
 import org.apache.fineract.portfolio.client.exception.ClientNotFoundException;
 import org.apache.fineract.portfolio.self.client.data.SelfClientDataValidator;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/clients")
 @Component
 @Tag(name = "Self Client", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfClientsApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/config/SelfServiceModuleIsEnabledCondition.java
similarity index 65%
copy from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiConstants.java
copy to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/config/SelfServiceModuleIsEnabledCondition.java
index a0cf67cbd0..fa4fe3e010 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/config/SelfServiceModuleIsEnabledCondition.java
@@ -16,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.api;
+package org.apache.fineract.portfolio.self.config;
 
-public final class DeviceRegistrationApiConstants {
+import org.apache.fineract.infrastructure.core.condition.PropertiesCondition;
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
 
-    private DeviceRegistrationApiConstants() {
+public class SelfServiceModuleIsEnabledCondition extends PropertiesCondition {
 
+    @Override
+    protected boolean matches(FineractProperties properties) {
+        return properties.getModule().getSelfService().isEnabled();
     }
-
-    public static final String clientIdParamName = "clientId";
-    public static final String registrationIdParamName = "registrationId";
-
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/config/SelfServiceWarning.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/config/SelfServiceWarning.java
new file mode 100644
index 0000000000..c9fd5d7fdf
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/config/SelfServiceWarning.java
@@ -0,0 +1,43 @@
+/**
+ * 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.fineract.portfolio.self.config;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.stereotype.Component;
+
+@Component
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
+@Slf4j
+public class SelfServiceWarning implements InitializingBean {
+
+    @Override
+    @SuppressFBWarnings("SLF4J_SIGN_ONLY_FORMAT")
+    public void afterPropertiesSet() throws Exception {
+        
log.warn("------------------------------------------------------------");
+        log.warn("                                                            
");
+        log.warn("DO NOT USE THIS IN PRODUCTION!");
+        log.warn("Self service capabilities of Fineract are NOT considered 
safe!");
+        log.warn("DO NOT USE THIS IN PRODUCTION!");
+        log.warn("                                                            
");
+        
log.warn("------------------------------------------------------------");
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/api/DeviceRegistrationApiConstants.java
similarity index 95%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiConstants.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/api/DeviceRegistrationApiConstants.java
index a0cf67cbd0..42ca444d19 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/api/DeviceRegistrationApiConstants.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.api;
+package org.apache.fineract.portfolio.self.device.api;
 
 public final class DeviceRegistrationApiConstants {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/api/DeviceRegistrationApiResource.java
similarity index 90%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiResource.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/api/DeviceRegistrationApiResource.java
index 91b8aff3a5..cb61251607 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/api/DeviceRegistrationApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/api/DeviceRegistrationApiResource.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.api;
+package org.apache.fineract.portfolio.self.device.api;
 
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
@@ -36,17 +36,20 @@ import java.util.Collection;
 import java.util.HashMap;
 import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationData;
-import 
org.apache.fineract.infrastructure.gcm.service.DeviceRegistrationReadPlatformService;
-import 
org.apache.fineract.infrastructure.gcm.service.DeviceRegistrationWritePlatformService;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistration;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistrationData;
+import 
org.apache.fineract.portfolio.self.device.service.DeviceRegistrationReadPlatformService;
+import 
org.apache.fineract.portfolio.self.device.service.DeviceRegistrationWritePlatformService;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/device/registration")
 @Component
 @Tag(name = "Device Registration", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class DeviceRegistrationApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistration.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistration.java
similarity index 97%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistration.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistration.java
index 6e13887b43..c94b0c22a3 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistration.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistration.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.domain;
+package org.apache.fineract.portfolio.self.device.domain;
 
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationData.java
similarity index 96%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationData.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationData.java
index 44247d4090..c5dc7c7040 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationData.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.domain;
+package org.apache.fineract.portfolio.self.device.domain;
 
 import java.time.OffsetDateTime;
 import lombok.Getter;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationRepository.java
similarity index 96%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationRepository.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationRepository.java
index 53f22fd7ef..68a0d25a5a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationRepository.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationRepository.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.domain;
+package org.apache.fineract.portfolio.self.device.domain;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationRepositoryWrapper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationRepositoryWrapper.java
similarity index 92%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationRepositoryWrapper.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationRepositoryWrapper.java
index c99c5b5233..e971ea5457 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/DeviceRegistrationRepositoryWrapper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/domain/DeviceRegistrationRepositoryWrapper.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.domain;
+package org.apache.fineract.portfolio.self.device.domain;
 
-import 
org.apache.fineract.infrastructure.gcm.exception.DeviceRegistrationNotFoundException;
+import 
org.apache.fineract.portfolio.self.device.exception.DeviceRegistrationNotFoundException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/exception/DeviceRegistrationNotFoundException.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/exception/DeviceRegistrationNotFoundException.java
similarity index 97%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/exception/DeviceRegistrationNotFoundException.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/exception/DeviceRegistrationNotFoundException.java
index a5f8aa0e22..3a0d92a491 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/exception/DeviceRegistrationNotFoundException.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/exception/DeviceRegistrationNotFoundException.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.exception;
+package org.apache.fineract.portfolio.self.device.exception;
 
 import 
org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
 import org.springframework.dao.EmptyResultDataAccessException;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationReadPlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationReadPlatformService.java
similarity index 88%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationReadPlatformService.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationReadPlatformService.java
index dd1e0490fd..3834b4e54b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationReadPlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationReadPlatformService.java
@@ -16,10 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.service;
+package org.apache.fineract.portfolio.self.device.service;
 
 import java.util.Collection;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationData;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistrationData;
 
 public interface DeviceRegistrationReadPlatformService {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationReadPlatformServiceImpl.java
similarity index 95%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationReadPlatformServiceImpl.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationReadPlatformServiceImpl.java
index c21e0c844c..203b569bdf 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationReadPlatformServiceImpl.java
@@ -16,17 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.service;
+package org.apache.fineract.portfolio.self.device.service;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.time.OffsetDateTime;
 import java.util.Collection;
 import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationData;
-import 
org.apache.fineract.infrastructure.gcm.exception.DeviceRegistrationNotFoundException;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.portfolio.client.data.ClientData;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistrationData;
+import 
org.apache.fineract.portfolio.self.device.exception.DeviceRegistrationNotFoundException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationWritePlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationWritePlatformService.java
similarity index 88%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationWritePlatformService.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationWritePlatformService.java
index f10975b609..d8b1f2b9b0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationWritePlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationWritePlatformService.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.service;
+package org.apache.fineract.portfolio.self.device.service;
 
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistration;
 
 public interface DeviceRegistrationWritePlatformService {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationWritePlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationWritePlatformServiceImpl.java
similarity index 95%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationWritePlatformServiceImpl.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationWritePlatformServiceImpl.java
index 09d54481ef..1b77f78bcd 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/service/DeviceRegistrationWritePlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/device/service/DeviceRegistrationWritePlatformServiceImpl.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.gcm.service;
+package org.apache.fineract.portfolio.self.device.service;
 
 import jakarta.persistence.EntityExistsException;
 import jakarta.persistence.PersistenceException;
@@ -24,11 +24,11 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.infrastructure.gcm.domain.DeviceRegistration;
-import 
org.apache.fineract.infrastructure.gcm.domain.DeviceRegistrationRepositoryWrapper;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
+import org.apache.fineract.portfolio.self.device.domain.DeviceRegistration;
+import 
org.apache.fineract.portfolio.self.device.domain.DeviceRegistrationRepositoryWrapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.orm.jpa.JpaSystemException;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
index 79b0e5b877..d87e353cb7 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
@@ -56,15 +56,18 @@ import 
org.apache.fineract.portfolio.loanaccount.exception.NotSupportedLoanTempl
 import 
org.apache.fineract.portfolio.loanaccount.guarantor.api.GuarantorsApiResource;
 import org.apache.fineract.portfolio.loanaccount.guarantor.data.GuarantorData;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import 
org.apache.fineract.portfolio.self.loanaccount.data.SelfLoansDataValidator;
 import 
org.apache.fineract.portfolio.self.loanaccount.service.AppuserLoansMapperReadService;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/loans")
 @Component
 @Tag(name = "Self Loans", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfLoansApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/pockets/api/PocketApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/pockets/api/PocketApiResource.java
index bc33cd3d73..62c9be04fa 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/pockets/api/PocketApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/pockets/api/PocketApiResource.java
@@ -43,13 +43,16 @@ import 
org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformS
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import 
org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
 import 
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import 
org.apache.fineract.portfolio.self.pockets.service.PocketAccountMappingReadPlatformService;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/pockets")
 @Component
 @Tag(name = "Pocket", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class PocketApiResource {
 
     private final PortfolioCommandSourceWritePlatformService 
commandsSourceWritePlatformService;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java
index 7569a08605..5149a87c88 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfLoanProductsApiResource.java
@@ -33,6 +33,8 @@ import lombok.RequiredArgsConstructor;
 import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanproduct.api.LoanProductsApiResource;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/loanproducts")
@@ -114,6 +116,7 @@ import org.springframework.stereotype.Component;
         + "If Specified as true, arrears will be identified based on original 
schedule.\n" + "allowAttributeOverrides\n"
         + "Specifies if select attributes may be overridden for individual 
loan accounts.")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfLoanProductsApiResource {
 
     private final LoanProductsApiResource loanProductsApiResource;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfSavingsProductsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfSavingsProductsApiResource.java
index f83c64e03b..4db3b2f723 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfSavingsProductsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfSavingsProductsApiResource.java
@@ -33,12 +33,15 @@ import lombok.RequiredArgsConstructor;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.api.SavingsProductsApiResource;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/savingsproducts")
 @Component
 @Tag(name = "Self Savings Products", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfSavingsProductsApiResource {
 
     private final SavingsProductsApiResource savingsProductsApiResource;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfShareProductsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfShareProductsApiResource.java
index 0b005291e2..b3e8ae73c1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfShareProductsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/products/api/SelfShareProductsApiResource.java
@@ -33,12 +33,15 @@ import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants;
 import org.apache.fineract.portfolio.products.api.ProductsApiResource;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/products/share")
 @Component
 @Tag(name = "Self Share Products", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfShareProductsApiResource {
 
     private final ProductsApiResource productsApiResource;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/registration/api/SelfServiceRegistrationApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/registration/api/SelfServiceRegistrationApiResource.java
index 4f4d777134..725079967e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/registration/api/SelfServiceRegistrationApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/registration/api/SelfServiceRegistrationApiResource.java
@@ -27,15 +27,18 @@ import jakarta.ws.rs.core.MediaType;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import 
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.apache.fineract.portfolio.self.registration.SelfServiceApiConstants;
 import 
org.apache.fineract.portfolio.self.registration.service.SelfServiceRegistrationWritePlatformService;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/registration")
 @Component
 @Tag(name = "Self Service Registration", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfServiceRegistrationApiResource {
 
     private final SelfServiceRegistrationWritePlatformService 
selfServiceRegistrationWritePlatformService;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/runreport/SelfRunReportApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/runreport/SelfRunReportApiResource.java
index 9de8297741..fa4bfdd1e9 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/runreport/SelfRunReportApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/runreport/SelfRunReportApiResource.java
@@ -37,6 +37,8 @@ import jakarta.ws.rs.core.UriInfo;
 import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.dataqueries.api.RunreportsApiResource;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/runreports")
@@ -51,6 +53,7 @@ import org.springframework.stereotype.Component;
         + "\n" + "ARGUMENTS\n"
         + "R_'parameter names' ... optional, No defaults The number and names 
of the parameters depend on the specific report and how it has been configured. 
R_officeId is an example parameter name.Note: the prefix R_ stands for 
ReportinggenericResultSetoptional, defaults to true If 'true' an optimised JSON 
format is returned suitable for tabular display of data. If 'false' a simple 
JSON format is returned. parameterType optional, The only valid value is 
'true'. If any other value is pro [...]
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfRunReportApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/savings/api/SelfSavingsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/savings/api/SelfSavingsApiResource.java
index 0239e385a2..f7c1cb8b03 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/savings/api/SelfSavingsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/savings/api/SelfSavingsApiResource.java
@@ -52,16 +52,19 @@ import 
org.apache.fineract.portfolio.savings.api.SavingsApiSetConstants;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
 import 
org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import 
org.apache.fineract.portfolio.self.savings.data.SelfSavingsAccountConstants;
 import 
org.apache.fineract.portfolio.self.savings.data.SelfSavingsDataValidator;
 import 
org.apache.fineract.portfolio.self.savings.service.AppuserSavingsMapperReadService;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/savingsaccounts")
 @Component
 @Tag(name = "Self Savings Account", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfSavingsApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java
index 58e35f8060..72be491d6e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java
@@ -33,7 +33,9 @@ import jakarta.ws.rs.core.MediaType;
 import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.security.api.AuthenticationApiResource;
 import 
org.apache.fineract.infrastructure.security.api.AuthenticationApiResourceSwagger;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -41,6 +43,7 @@ import org.springframework.stereotype.Component;
 @Path("/v1/self/authentication")
 @Tag(name = "Self Authentication", description = "Authenticates the 
credentials provided and returns the set roles and permissions allowed")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfAuthenticationApiResource {
 
     private final AuthenticationApiResource authenticationApiResource;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserApiResource.java
index 69053d53c5..b627aafd72 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserApiResource.java
@@ -40,14 +40,17 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.apache.fineract.useradministration.api.UsersApiResource;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/user")
 @Component
 @Tag(name = "Self User", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfUserApiResource {
 
     private final UsersApiResource usersApiResource;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserDetailsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserDetailsApiResource.java
index 7b74b5dc18..ef31febdab 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserDetailsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfUserDetailsApiResource.java
@@ -30,7 +30,9 @@ import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.core.MediaType;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.infrastructure.security.api.UserDetailsApiResource;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/userdetails")
@@ -38,6 +40,7 @@ import org.springframework.stereotype.Component;
 @ConditionalOnProperty("fineract.security.oauth.enabled")
 @Tag(name = "Self User Details", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfUserDetailsApiResource {
 
     private final UserDetailsApiResource userDetailsApiResource;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/shareaccounts/api/SelfShareAccountsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/shareaccounts/api/SelfShareAccountsApiResource.java
index f1907825f0..2f42ab38ac 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/shareaccounts/api/SelfShareAccountsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/shareaccounts/api/SelfShareAccountsApiResource.java
@@ -57,17 +57,20 @@ import 
org.apache.fineract.portfolio.client.exception.ClientNotFoundException;
 import org.apache.fineract.portfolio.products.data.ProductData;
 import 
org.apache.fineract.portfolio.products.service.ShareProductReadPlatformService;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import 
org.apache.fineract.portfolio.self.shareaccounts.data.SelfShareAccountsDataValidator;
 import 
org.apache.fineract.portfolio.self.shareaccounts.service.AppUserShareAccountsMapperReadPlatformService;
 import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
 import 
org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/self/shareaccounts")
 @Component
 @Tag(name = "Self Share Accounts", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfShareAccountsApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfScorecardApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfScorecardApiResource.java
index 16af1027e1..24eac5f78d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfScorecardApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfScorecardApiResource.java
@@ -32,9 +32,11 @@ import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.portfolio.client.exception.ClientNotFoundException;
 import 
org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.apache.fineract.spm.api.ScorecardApiResource;
 import org.apache.fineract.spm.data.ScorecardData;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -42,6 +44,7 @@ import 
org.springframework.transaction.annotation.Transactional;
 @Component
 @Tag(name = "Self Score Card", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfScorecardApiResource {
 
     private final PlatformSecurityContext context;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfSpmApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfSpmApiResource.java
index d288e8dcf5..483b41da08 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfSpmApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/spm/api/SelfSpmApiResource.java
@@ -28,8 +28,10 @@ import jakarta.ws.rs.core.MediaType;
 import java.util.List;
 import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import 
org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
 import org.apache.fineract.spm.api.SpmApiResource;
 import org.apache.fineract.spm.data.SurveyData;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -37,6 +39,7 @@ import 
org.springframework.transaction.annotation.Transactional;
 @Component
 @Tag(name = "Self Spm", description = "")
 @RequiredArgsConstructor
+@Conditional(SelfServiceModuleIsEnabledCondition.class)
 public class SelfSpmApiResource {
 
     private final PlatformSecurityContext securityContext;
diff --git a/fineract-provider/src/main/resources/application.properties 
b/fineract-provider/src/main/resources/application.properties
index a627c44d21..3dd6a5a662 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -183,6 +183,8 @@ 
fineract.sampling.samplingRate=${FINERACT_SAMPLING_RATE:1000}
 fineract.sampling.sampledClasses=${FINERACT_SAMPLED_CLASSES:}
 fineract.sampling.resetPeriodSec=${FINERACT_SAMPLING_RESET_PERIOD_IN_SEC:60}
 
+#Modules
+fineract.module.self-service.enabled=${FINERACT_MODULE_SELF_SERVICE_ENABLED:false}
 fineract.module.investor.enabled=${FINERACT_MODULE_INVESTOR_ENABLED:true}
 
 fineract.insecure-http-client=${FINERACT_INSECURE_HTTP_CLIENT:true}
diff --git a/fineract-provider/src/test/resources/application-test.properties 
b/fineract-provider/src/test/resources/application-test.properties
index a7d6336e62..6d5f46f4db 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -105,6 +105,7 @@ fineract.sampling.enabled=false
 fineract.sampling.sampledClasses=
 
 fineract.module.investor.enabled=true
+fineract.module.self-service.enabled=true
 
 # sql validation
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountsExternalIdTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountsExternalIdTest.java
index 2f2b13621d..ee1639b1d9 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountsExternalIdTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountsExternalIdTest.java
@@ -144,7 +144,7 @@ public class SavingsAccountsExternalIdTest extends 
IntegrationTest {
         request.dateFormat(dateFormat);
         request.setLocale(locale);
         request.setActivatedOnDate(formattedDate);
-        Response<DeleteSavingsAccountsAccountIdResponse> response = 
okR(fineractClient().savingsAccounts.delete20(EXTERNAL_ID));
+        Response<DeleteSavingsAccountsAccountIdResponse> response = 
okR(fineractClient().savingsAccounts.delete19(EXTERNAL_ID));
 
         assertThat(response.isSuccessful()).isTrue();
         assertThat(response.body()).isNotNull();

Reply via email to