diff --git a/.github/workflows/build-oauth2.yml b/.github/workflows/build-oauth2.yml deleted file mode 100644 index 7b715fe47..000000000 --- a/.github/workflows/build-oauth2.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Fineract Gradle build - oauth2 -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-20.04 - - services: - mariad: - image: mariadb:10.6 - ports: - - 3306:3306 - env: - MARIADB_ROOT_PASSWORD: mysql - options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 - - mock-oauth2-server: - image: ghcr.io/navikt/mock-oauth2-server:0.4.0 - ports: - - 9000:9000 - env: - SERVER_PORT: 9000 - JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }' - - env: - TZ: Asia/Kolkata - steps: - - name: Set up cache - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-oauth2-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-oauth2- - - name: Checkout - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'zulu' - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b - - name: Verify MariaDB connection - run: | - while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do - sleep 1 - done - - name: Initialise databases - run: | - ./gradlew --no-daemon -q createDB -PdbName=fineract_tenants - ./gradlew --no-daemon -q createDB -PdbName=fineract_default - - name: Install additional software - run: | - sudo apt-get update - sudo apt-get install ghostscript -y - - name: Build & Test - run: ./gradlew --no-daemon -q --console=plain build test --fail-fast -x :integration-tests:test -x :twofactor-tests:test -Psecurity=oauth diff --git a/.github/workflows/build-twofactor.yml b/.github/workflows/build-twofactor.yml deleted file mode 100644 index aac714140..000000000 --- a/.github/workflows/build-twofactor.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Fineract Gradle build - twofactor -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-20.04 - - services: - mariad: - image: mariadb:10.6 - ports: - - 3306:3306 - env: - MARIADB_ROOT_PASSWORD: mysql - options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 - - env: - TZ: Asia/Kolkata - steps: - - name: Set up cache - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-twofactor-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle-twofactor- - - name: Checkout - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'zulu' - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b - - name: Verify MariaDB connection - run: | - while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do - sleep 1 - done - - name: Initialise databases - run: | - ./gradlew --no-daemon -q createDB -PdbName=fineract_tenants - ./gradlew --no-daemon -q createDB -PdbName=fineract_default - - name: Install additional software - run: | - sudo apt-get update - sudo apt-get install ghostscript -y - - name: Build & Test - run: ./gradlew --no-daemon -q --console=plain build test --fail-fast -x :integration-tests:test -x :oauth2-tests:test -Ptwofactor=enabled diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e89ac642..6ce6f08ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,6 +13,15 @@ jobs: env: MARIADB_ROOT_PASSWORD: mysql options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 + + mock-oauth2-server: + image: ghcr.io/navikt/mock-oauth2-server:0.4.0 + ports: + - 9000:9000 + env: + SERVER_PORT: 9000 + JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }' + env: TZ: Asia/Kolkata steps: @@ -22,9 +31,9 @@ jobs: path: | ~/.gradle/caches ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-basicauth-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | - ${{ runner.os }}-gradle-basicauth- + ${{ runner.os }}-gradle- - name: Checkout uses: actions/checkout@v2 - name: Set up JDK 11 @@ -47,5 +56,12 @@ jobs: run: | sudo apt-get update sudo apt-get install ghostscript -y - - name: Build & Test + + - name: Basic Auth Build & Test run: ./gradlew --no-daemon -q --console=plain licenseMain licenseTest check build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test + + - name: 2FA Build & Test + run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast + + - name: OAuth2 Build & Test + run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast diff --git a/.gitignore b/.gitignore index e56ba7eb5..0ae3f4373 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ build catalina.base_IS_UNDEFINED/ keystore.jks bin/ -fineract-provider/src/main/resources/application.properties .lock fineract-provider/out/ fineract-provider/config/swagger/config.json diff --git a/README.md b/README.md index d276d3e50..9c26e5835 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,50 @@ The tenants database connection details are configured [via environment variable java -jar fineract-provider.jar +Security +============ +NOTE: The HTTP Basic and OAuth2 authentication schemes are mutually exclusive. You can't enable them both at the same time. Fineract checks these settings on startup and will fail if more than one authentication scheme is enabled. + +HTTP Basic Authentication +------------ +By default Fineract is configured with a HTTP Basic Authentication scheme, so you actually don't have to do anything if you want to use it. But if you would like to explicitly choose this authentication scheme then there are two ways to enable it: +1. Use environment variables (best choice if you run with Docker Compose): +``` +FINERACT_SECURITY_BASICAUTH_ENABLED=true +FINERACT_SECURITY_OAUTH_ENABLED=false +``` +2. Use JVM parameters (best choice if you run the Spring Boot JAR): +``` +java -Dfineract.security.basicauth.enabled=true -Dfineract.security.oauth.enabled=false -jar fineract-provider.jar +``` + +OAuth2 Authentication +------------ +There is also an OAuth2 authentication scheme available. Again, two ways to enable it: +1. Use environment variables (best choice if you run with Docker Compose): +``` +FINERACT_SECURITY_BASICAUTH_ENABLED=false +FINERACT_SECURITY_OAUTH_ENABLED=true +``` +2. Use JVM parameters (best choice if you run the Spring Boot JAR): +``` +java -Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth.enabled=true -jar fineract-provider.jar +``` + +Two Factor Authentication +------------ +You can also enable 2FA authentication. Depending on how you start Fineract add the following: + +1. Use environment variable (best choice if you run with Docker Compose): +``` +FINERACT_SECURITY_2FA_ENABLED=true +``` +2. Use JVM parameter (best choice if you run the Spring Boot JAR): +``` +-Dfineract.security.2fa.enabled=true +``` + + Instructions to build a WAR file ============ 1. Clone the repository or download and extract the archive file to your local directory. diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index f034777d4..0d8d44aef 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -155,37 +155,6 @@ configurations { apply from: 'dependencies.gradle' -/* Enable Oauth2 authentication based on environment, default to HTTP basic auth */ -if (project.hasProperty('security') && project.getProperty('security') == 'oauth') { - if(project.hasProperty('twofactor') && project.getProperty('twofactor') == 'enabled') { - copy { - from './properties/oauth/twofactor/' - into 'src/main/resources/' - include '*.properties' - } - } else { - copy { - from './properties/oauth/' - into 'src/main/resources/' - include '*.properties' - } - } -} else { - if(project.hasProperty('twofactor') && project.getProperty('twofactor') == 'enabled') { - copy { - from './properties/basicauth/twofactor/' - into 'src/main/resources/' - include '*.properties' - } - } else { - copy { - from './properties/basicauth/' - into 'src/main/resources/' - include '*.properties' - } - } -} - // Configuration for the modernizer plugin // https://github.com/andygoossens/gradle-modernizer-plugin modernizer { @@ -324,7 +293,6 @@ jib { ] args = [ '-Duser.home=/tmp', - '-Dspring.profiles.active=basicauth', '-Dfile.encoding=UTF-8', '-Duser.timezone=UTC', '-Djava.security.egd=file:/dev/./urandom' diff --git a/fineract-provider/properties/basicauth/twofactor/application.properties b/fineract-provider/properties/basicauth/twofactor/application.properties deleted file mode 100644 index 03788ecfa..000000000 --- a/fineract-provider/properties/basicauth/twofactor/application.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# 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. -# - -spring.profiles.default=basicauth -spring.profiles.active=basicauth,twofactor -management.health.jms.enabled=false - -# FINERACT 1296 -management.endpoint.health.probes.enabled=true -management.health.livenessState.enabled=true -management.health.readinessState.enabled=true - -# FINERACT-883 -management.info.git.mode=FULL -management.endpoints.web.exposure.include=health,info - -# FINERACT-914 -server.forward-headers-strategy=framework diff --git a/fineract-provider/properties/oauth/application.properties b/fineract-provider/properties/oauth/application.properties deleted file mode 100644 index 6936db527..000000000 --- a/fineract-provider/properties/oauth/application.properties +++ /dev/null @@ -1,37 +0,0 @@ -# -# 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. -# - -spring.profiles.default=basicauth -spring.profiles.active=oauth -management.health.jms.enabled=false - -# FINERACT 1296 -management.endpoint.health.probes.enabled=true -management.health.livenessState.enabled=true -management.health.readinessState.enabled=true - -# FINERACT-883 -management.info.git.mode=FULL -management.endpoints.web.exposure.include=health,info - -# FINERACT-914 -server.forward-headers-strategy=framework - -# OAuth authorisation server endpoint -spring.security.oauth2.resourceserver.jwt.issuer-uri: http://localhost:9000/auth/realms/fineract 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 a2226c922..32202a67b 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 @@ -29,10 +29,10 @@ import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticatio import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService; import org.apache.fineract.infrastructure.security.vote.SelfServiceUserAccessVote; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; import org.springframework.core.convert.converter.Converter; import org.springframework.http.HttpMethod; import org.springframework.security.access.AccessDecisionManager; @@ -59,7 +59,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi import org.springframework.security.web.context.SecurityContextPersistenceFilter; @Configuration -@Profile("oauth") +@ConditionalOnProperty("fineract.security.oauth.enabled") @EnableGlobalMethodSecurity(prePostEnabled = true) public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter { 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 4269790f4..8fac76759 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 @@ -23,10 +23,10 @@ import org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthen import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter; import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -42,7 +42,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi import org.springframework.security.web.context.SecurityContextPersistenceFilter; @Configuration -@Profile("basicauth") +@ConditionalOnProperty("fineract.security.basicauth.enabled") @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityValidationConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityValidationConfig.java new file mode 100644 index 000000000..6954d46e5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityValidationConfig.java @@ -0,0 +1,50 @@ +/** + * 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.infrastructure.core.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SecurityValidationConfig { + + @Value("${fineract.security.basicauth.enabled}") + private Boolean basicAuthEnabled; + + @Value("${fineract.security.oauth.enabled}") + private Boolean oauthEnabled; + + @PostConstruct + public void validate() { + // NOTE: avoid NPE if these values are not set + if (!Boolean.TRUE.equals(basicAuthEnabled) && !Boolean.TRUE.equals(oauthEnabled)) { + // NOTE: while we are already doing consistency checks we might as well cover this case; should not happen + // as defaults are set in application.properties + throw new IllegalArgumentException( + "No authentication scheme selected. Please decide if you want to use basic OR OAuth2 authentication."); + } + + if (Boolean.TRUE.equals(basicAuthEnabled) && Boolean.TRUE.equals(oauthEnabled)) { + throw new IllegalArgumentException( + "Too many authentication schemes selected. Please decide if you want to use basic OR OAuth2 authentication."); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java index fc3ed602a..91efd8ecd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java @@ -44,14 +44,14 @@ import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer import org.apache.fineract.infrastructure.security.constants.TwoFactorConstants; import org.apache.fineract.infrastructure.security.data.AuthenticatedUserData; import org.apache.fineract.infrastructure.security.service.SpringSecurityPlatformSecurityContext; -import org.apache.fineract.infrastructure.security.service.TwoFactorUtils; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.useradministration.data.RoleData; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.Role; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Profile; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Scope; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -61,11 +61,14 @@ import org.springframework.stereotype.Component; @Component @Scope("singleton") -@Profile("basicauth") +@ConditionalOnProperty("fineract.security.basicauth.enabled") @Path("/authentication") @Tag(name = "Authentication HTTP Basic", description = "An API capability that allows client applications to verify authentication details using HTTP Basic Authentication.") public class AuthenticationApiResource { + @Value("${fineract.security.2fa.enabled}") + private boolean twoFactorEnabled; + public static class AuthenticateRequest { public String username; @@ -75,19 +78,17 @@ public class AuthenticationApiResource { private final DaoAuthenticationProvider customAuthenticationProvider; private final ToApiJsonSerializer apiJsonSerializerService; private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext; - private final TwoFactorUtils twoFactorUtils; private final ClientReadPlatformService clientReadPlatformService; @Autowired public AuthenticationApiResource( @Qualifier("customAuthenticationProvider") final DaoAuthenticationProvider customAuthenticationProvider, final ToApiJsonSerializer apiJsonSerializerService, - final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext, TwoFactorUtils twoFactorUtils, + final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext, ClientReadPlatformService aClientReadPlatformService) { this.customAuthenticationProvider = customAuthenticationProvider; this.apiJsonSerializerService = apiJsonSerializerService; this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext; - this.twoFactorUtils = twoFactorUtils; clientReadPlatformService = aClientReadPlatformService; } @@ -143,7 +144,7 @@ public class AuthenticationApiResource { final EnumOptionData organisationalRole = principal.organisationalRoleData(); - boolean isTwoFactorRequired = twoFactorUtils.isTwoFactorAuthEnabled() + boolean isTwoFactorRequired = this.twoFactorEnabled && !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION); Long userId = principal.getId(); if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorApiResource.java index 839c050ad..91617dd6e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorApiResource.java @@ -45,13 +45,13 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte import org.apache.fineract.infrastructure.security.service.TwoFactorService; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Path("/twofactor") @Component -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") @Scope("singleton") @Tag(name = "Two Factor", description = "") public class TwoFactorApiResource { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorConfigurationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorConfigurationApiResource.java index c6980ebdc..e76af9af2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorConfigurationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/TwoFactorConfigurationApiResource.java @@ -33,7 +33,7 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.TwoFactorConfigurationService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -42,7 +42,7 @@ import org.springframework.stereotype.Component; @Produces({ MediaType.APPLICATION_JSON }) @Component @Scope("singleton") -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class TwoFactorConfigurationApiResource { private final String resourceNameForPermissions = "TWOFACTOR_CONFIG"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/UserDetailsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/UserDetailsApiResource.java index 64e96bf0c..2ee5fcc7e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/UserDetailsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/UserDetailsApiResource.java @@ -37,12 +37,12 @@ import org.apache.fineract.infrastructure.security.constants.TwoFactorConstants; import org.apache.fineract.infrastructure.security.data.AuthenticatedOauthUserData; import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken; import org.apache.fineract.infrastructure.security.service.SpringSecurityPlatformSecurityContext; -import org.apache.fineract.infrastructure.security.service.TwoFactorUtils; import org.apache.fineract.useradministration.data.RoleData; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.Role; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Scope; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; @@ -54,22 +54,22 @@ import org.springframework.stereotype.Component; */ @Path("/userdetails") @Component -@Profile("oauth") +@ConditionalOnProperty("fineract.security.oauth.enabled") @Scope("singleton") - @Tag(name = "Fetch authenticated user details", description = "") public class UserDetailsApiResource { private final ToApiJsonSerializer apiJsonSerializerService; private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext; - private final TwoFactorUtils twoFactorUtils; + + @Value("${fineract.security.2fa.enabled}") + private boolean twoFactorEnabled; @Autowired public UserDetailsApiResource(final ToApiJsonSerializer apiJsonSerializerService, - final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext, final TwoFactorUtils twoFactorUtils) { + final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext) { this.apiJsonSerializerService = apiJsonSerializerService; this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext; - this.twoFactorUtils = twoFactorUtils; } @GET @@ -116,16 +116,15 @@ public class UserDetailsApiResource { final EnumOptionData organisationalRole = principal.organisationalRoleData(); - final boolean requireTwoFactorAuth = twoFactorUtils.isTwoFactorAuthEnabled() + boolean isTwoFactorRequired = this.twoFactorEnabled && !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION); - if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) { authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), principal.getId(), - authentication.getToken().getTokenValue(), requireTwoFactorAuth); + authentication.getToken().getTokenValue(), isTwoFactorRequired); } else { authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), officeId, officeName, staffId, staffDisplayName, organisationalRole, roles, permissions, principal.getId(), authentication.getToken().getTokenValue(), - requireTwoFactorAuth); + isTwoFactorRequired); } return this.apiJsonSerializerService.serialize(authenticatedUserData); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/InvalidateTFAccessTokenCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/InvalidateTFAccessTokenCommandHandler.java index 903b5cf1c..46c8062f7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/InvalidateTFAccessTokenCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/InvalidateTFAccessTokenCommandHandler.java @@ -43,13 +43,13 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte import org.apache.fineract.infrastructure.security.service.TwoFactorService; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @CommandType(entity = "TWOFACTOR_ACCESSTOKEN", action = "INVALIDATE") -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class InvalidateTFAccessTokenCommandHandler implements NewCommandSourceHandler { private final TwoFactorService twoFactorService; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/UpdateTwoFactorConfigCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/UpdateTwoFactorConfigCommandHandler.java index 58b027b7f..d10331542 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/UpdateTwoFactorConfigCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/command/UpdateTwoFactorConfigCommandHandler.java @@ -27,13 +27,13 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild import org.apache.fineract.infrastructure.security.data.TwoFactorConfigurationValidator; import org.apache.fineract.infrastructure.security.service.TwoFactorConfigurationService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @CommandType(entity = "TWOFACTOR_CONFIGURATION", action = "UPDATE") -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class UpdateTwoFactorConfigCommandHandler implements NewCommandSourceHandler { private final TwoFactorConfigurationService configurationService; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/data/TwoFactorConfigurationValidator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/data/TwoFactorConfigurationValidator.java index bea4599e5..6888a7ebd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/data/TwoFactorConfigurationValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/data/TwoFactorConfigurationValidator.java @@ -32,11 +32,11 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.security.constants.TwoFactorConfigurationConstants; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; @Component -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class TwoFactorConfigurationValidator { private final FromJsonHelper fromJsonHelper; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/OTPRequestRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/OTPRequestRepository.java index 031ac0f61..eaf3f4354 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/OTPRequestRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/OTPRequestRepository.java @@ -21,12 +21,12 @@ package org.apache.fineract.infrastructure.security.domain; import java.util.concurrent.ConcurrentHashMap; import org.apache.fineract.infrastructure.security.data.OTPRequest; import org.apache.fineract.useradministration.domain.AppUser; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Repository; import org.springframework.util.Assert; @Repository -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") @SuppressWarnings({ "MemberName" }) public class OTPRequestRepository { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TFAccessTokenRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TFAccessTokenRepository.java index b840eae9e..aaed99f4d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TFAccessTokenRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TFAccessTokenRepository.java @@ -19,11 +19,11 @@ package org.apache.fineract.infrastructure.security.domain; import org.apache.fineract.useradministration.domain.AppUser; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public interface TFAccessTokenRepository extends JpaRepository, JpaSpecificationExecutor { TFAccessToken findByUserAndToken(AppUser user, String token); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TwoFactorConfigurationRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TwoFactorConfigurationRepository.java index 508e9a83c..9692d39c2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TwoFactorConfigurationRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/domain/TwoFactorConfigurationRepository.java @@ -19,11 +19,11 @@ package org.apache.fineract.infrastructure.security.domain; import java.util.List; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public interface TwoFactorConfigurationRepository extends JpaRepository, JpaSpecificationExecutor { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java index 64e40b8e0..0de565140 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java @@ -27,7 +27,7 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -43,7 +43,7 @@ import org.springframework.stereotype.Service; * This filter adds 'TWOFACTOR_AUTHENTICATED' authority to every authenticated platform user. */ @Service -@Profile("!twofactor") +@ConditionalOnProperty(name = "fineract.security.2fa.enabled", havingValue = "false") public class InsecureTwoFactorAuthenticationFilter extends TwoFactorAuthenticationFilter { public InsecureTwoFactorAuthenticationFilter() { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java index b97c3b045..c29fbdbef 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java @@ -38,7 +38,7 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; @@ -59,7 +59,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi * If multi-tenant and basic auth credentials are invalid, a http error response is returned. */ -@Profile("basicauth") +@ConditionalOnProperty("fineract.security.basicauth.enabled") public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFilter { private static boolean firstRequestProcessed = false; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java index bbc23de08..0638c7302 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java @@ -38,7 +38,7 @@ import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetail import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.web.filter.GenericFilterBean; @@ -55,7 +55,7 @@ import org.springframework.web.filter.GenericFilterBean; * Used to support Oauth2 authentication and the service is loaded only when "oauth" profile is active. */ @Service -@Profile("oauth") +@ConditionalOnProperty("fineract.security.oauth.enabled") public class TenantAwareTenantIdentifierFilter extends GenericFilterBean { private static boolean firstRequestProcessed = false; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java index 14dff4b68..a5ae91e35 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java @@ -34,7 +34,7 @@ import org.apache.fineract.infrastructure.security.domain.TFAccessToken; import org.apache.fineract.infrastructure.security.service.TwoFactorService; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -57,7 +57,7 @@ import org.springframework.web.filter.GenericFilterBean; * authority regardless of the value of the 'Fineract-Platform-TFA-Token' header. */ @Service -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class TwoFactorAuthenticationFilter extends GenericFilterBean { private final TwoFactorService twoFactorService; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorConfigurationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorConfigurationServiceImpl.java index 31babfc79..a01eaf8c7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorConfigurationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorConfigurationServiceImpl.java @@ -36,13 +36,13 @@ import org.apache.fineract.infrastructure.security.domain.TwoFactorConfiguration import org.apache.fineract.infrastructure.security.domain.TwoFactorConfigurationRepository; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; -import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @Service -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class TwoFactorConfigurationServiceImpl implements TwoFactorConfigurationService { private static final String DEFAULT_EMAIL_SUBJECT = "Fineract Two-Factor Authentication Token"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorServiceImpl.java index 8132d68c3..0134950b0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorServiceImpl.java @@ -39,14 +39,14 @@ import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository; import org.apache.fineract.infrastructure.sms.scheduler.SmsMessageScheduledJobService; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; -import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @Service -@Profile("twofactor") +@ConditionalOnProperty("fineract.security.2fa.enabled") public class TwoFactorServiceImpl implements TwoFactorService { private final AccessTokenGenerationService accessTokenGenerationService; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorUtils.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorUtils.java deleted file mode 100644 index ee435dbb4..000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/service/TwoFactorUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * 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.infrastructure.security.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; - -@Component -public class TwoFactorUtils { - - private static final String TWO_FACTOR_PROFILE_NAME = "twofactor"; - - private final Environment environment; - - @Autowired - public TwoFactorUtils(Environment environment) { - this.environment = environment; - } - - public boolean isTwoFactorAuthEnabled() { - for (final String profile : this.environment.getActiveProfiles()) { - if (TWO_FACTOR_PROFILE_NAME.equals(profile)) { - return true; - } - } - return false; - } -} 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 371d72cac..cbdd50c9e 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 @@ -31,13 +31,13 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.fineract.infrastructure.security.api.AuthenticationApiResource; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("singleton") -@Profile("basicauth") +@ConditionalOnProperty("fineract.security.basicauth.enabled") @Path("/self/authentication") @Tag(name = "Self Authentication", description = "Authenticates the credentials provided and returns the set roles and permissions allowed") public class SelfAuthenticationApiResource { 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 2104cdbeb..bbacd50d6 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,13 +30,13 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.fineract.infrastructure.security.api.UserDetailsApiResource; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Path("/self/userdetails") @Component -@Profile("oauth") +@ConditionalOnProperty("fineract.security.oauth.enabled") @Scope("singleton") @Tag(name = "Self User Details", description = "") diff --git a/fineract-provider/properties/oauth/twofactor/application.properties b/fineract-provider/src/main/resources/application.properties similarity index 78% rename from fineract-provider/properties/oauth/twofactor/application.properties rename to fineract-provider/src/main/resources/application.properties index 3a2e01d38..b4e3949b1 100644 --- a/fineract-provider/properties/oauth/twofactor/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -17,8 +17,10 @@ # under the License. # -spring.profiles.default=basicauth -spring.profiles.active=oauth,twofactor +fineract.security.basicauth.enabled=${FINERACT_SECURITY_BASICAUTH_ENABLED:true} +fineract.security.oauth.enabled=${FINERACT_SECURITY_OAUTH_ENABLED:false} +fineract.security.2fa.enabled=${FINERACT_SECURITY_2FA_ENABLED:false} + management.health.jms.enabled=false # FINERACT 1296 @@ -34,4 +36,4 @@ management.endpoints.web.exposure.include=health,info server.forward-headers-strategy=framework # OAuth authorisation server endpoint -spring.security.oauth2.resourceserver.jwt.issuer-uri: http://localhost:9000/auth/realms/fineract +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000/auth/realms/fineract diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerProviderTest.java b/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerProviderTest.java index 30baef962..2f776bc9f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerProviderTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerProviderTest.java @@ -29,14 +29,14 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; @ExtendWith(SpringExtension.class) +@TestPropertySource("classpath:application-test.properties") @WebAppConfiguration -@ActiveProfiles("basicauth") @ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class) public class CommandHandlerProviderTest { diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/SpringConfigurationTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/SpringConfigurationTest.java index a6d23e442..7a2627f4f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/SpringConfigurationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/SpringConfigurationTest.java @@ -20,8 +20,8 @@ package org.apache.fineract.infrastructure.configuration.spring; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; @@ -34,8 +34,8 @@ import org.springframework.test.context.web.WebAppConfiguration; * sufficient (as long as the TestsWithoutDatabaseAndNoJobsConfiguration used extends AbstractApplicationConfiguration). */ @ExtendWith(SpringExtension.class) +@TestPropertySource("classpath:application-test.properties") @WebAppConfiguration -@ActiveProfiles("basicauth") @ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class) public class SpringConfigurationTest { diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java index 4ce3cb8e2..1f5190098 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java @@ -24,6 +24,9 @@ import org.apache.fineract.infrastructure.core.service.TenantDatabaseUpgradeServ import org.apache.fineract.infrastructure.jobs.service.JobRegisterService; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; /** * Spring @Configuration which does not require a running database. It also does not load any job configuration (as they @@ -65,4 +68,10 @@ public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicat DataSource mockDataSource = Mockito.mock(DataSource.class, Mockito.RETURNS_MOCKS); return mockDataSource; } + + @Bean + @Primary + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/AbstractSpringBootWithMariaDB4jIntegrationTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/AbstractSpringBootWithMariaDB4jIntegrationTest.java index 39288cf4b..4ee62bcd4 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/AbstractSpringBootWithMariaDB4jIntegrationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/AbstractSpringBootWithMariaDB4jIntegrationTest.java @@ -21,14 +21,14 @@ package org.apache.fineract.infrastructure.core.boot.tests; import org.apache.fineract.ServerWithMariaDB4jApplication; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; @ExtendWith(SpringExtension.class) @SpringBootTest(classes = ServerWithMariaDB4jApplication.Configuration.class) +@TestPropertySource("classpath:application-test.properties") @WebAppConfiguration -@ActiveProfiles("basicauth") public abstract class AbstractSpringBootWithMariaDB4jIntegrationTest { // do NOT put any helper methods here! diff --git a/fineract-provider/properties/basicauth/application.properties b/fineract-provider/src/test/resources/application-test.properties similarity index 90% rename from fineract-provider/properties/basicauth/application.properties rename to fineract-provider/src/test/resources/application-test.properties index be392eb03..30b680b8c 100644 --- a/fineract-provider/properties/basicauth/application.properties +++ b/fineract-provider/src/test/resources/application-test.properties @@ -17,7 +17,10 @@ # under the License. # -spring.profiles.default=basicauth +fineract.security.basicauth.enabled=true +fineract.security.oauth.enabled=false +fineract.security.2fa.enabled=false + management.health.jms.enabled=false # FINERACT 1296 diff --git a/oauth2-tests/build.gradle b/oauth2-tests/build.gradle index f704877b3..fd20ac4ac 100644 --- a/oauth2-tests/build.gradle +++ b/oauth2-tests/build.gradle @@ -45,7 +45,7 @@ cargo { } startStopTimeout = 240000 containerProperties { - property 'cargo.start.jvmargs', '-Dspring.profiles.active=oauth' + property 'cargo.start.jvmargs', '-Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth.enabled=true -Dfineract.security.2fa.enabled=false' property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks") property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.httpSecure', true diff --git a/twofactor-tests/build.gradle b/twofactor-tests/build.gradle index aa91bb01e..e5c45c2da 100644 --- a/twofactor-tests/build.gradle +++ b/twofactor-tests/build.gradle @@ -45,7 +45,7 @@ cargo { } startStopTimeout = 240000 containerProperties { - property 'cargo.start.jvmargs', '-Dspring.profiles.active=twofactor,basicauth' + property 'cargo.start.jvmargs', '-Dfineract.security.basicauth.enabled=true -Dfineract.security.oauth.enabled=false -Dfineract.security.2fa.enabled=true' property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks") property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.httpSecure', true diff --git a/twofactor-tests/src/test/java/org/apache/fineract/twofactortests/TwoFactorAuthenticationTest.java b/twofactor-tests/src/test/java/org/apache/fineract/twofactortests/TwoFactorAuthenticationTest.java index e3703b467..82692988d 100644 --- a/twofactor-tests/src/test/java/org/apache/fineract/twofactortests/TwoFactorAuthenticationTest.java +++ b/twofactor-tests/src/test/java/org/apache/fineract/twofactortests/TwoFactorAuthenticationTest.java @@ -111,7 +111,7 @@ public class TwoFactorAuthenticationTest { .log().ifError().when().post("/fineract-provider/api/v1/authentication?" + TENANT_IDENTIFIER).asString(); assertFalse(StringUtils.isBlank(json)); Boolean key = JsonPath.with(json).get("isTwoFactorAuthenticationRequired"); - assertEquals(key, true); + assertEquals(true, key); } @Test