Simplify build for different auth strategies

This commit is contained in:
Aleksandar Vidakovic
2022-01-03 06:15:04 +08:00
committed by Petri Tuomola
parent c691c11699
commit 907f932abe
39 changed files with 194 additions and 331 deletions
-60
View File
@@ -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
-52
View File
@@ -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
+19 -3
View File
@@ -13,6 +13,15 @@ jobs:
env: env:
MARIADB_ROOT_PASSWORD: mysql MARIADB_ROOT_PASSWORD: mysql
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 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: env:
TZ: Asia/Kolkata TZ: Asia/Kolkata
steps: steps:
@@ -22,9 +31,9 @@ jobs:
path: | path: |
~/.gradle/caches ~/.gradle/caches
~/.gradle/wrapper ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-basicauth-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: | restore-keys: |
${{ runner.os }}-gradle-basicauth- ${{ runner.os }}-gradle-
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Set up JDK 11 - name: Set up JDK 11
@@ -47,5 +56,12 @@ jobs:
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install ghostscript -y 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 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
-1
View File
@@ -17,7 +17,6 @@ build
catalina.base_IS_UNDEFINED/ catalina.base_IS_UNDEFINED/
keystore.jks keystore.jks
bin/ bin/
fineract-provider/src/main/resources/application.properties
.lock .lock
fineract-provider/out/ fineract-provider/out/
fineract-provider/config/swagger/config.json fineract-provider/config/swagger/config.json
+44
View File
@@ -59,6 +59,50 @@ The tenants database connection details are configured [via environment variable
java -jar fineract-provider.jar 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 Instructions to build a WAR file
============ ============
1. Clone the repository or download and extract the archive file to your local directory. 1. Clone the repository or download and extract the archive file to your local directory.
-32
View File
@@ -155,37 +155,6 @@ configurations {
apply from: 'dependencies.gradle' 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 // Configuration for the modernizer plugin
// https://github.com/andygoossens/gradle-modernizer-plugin // https://github.com/andygoossens/gradle-modernizer-plugin
modernizer { modernizer {
@@ -324,7 +293,6 @@ jib {
] ]
args = [ args = [
'-Duser.home=/tmp', '-Duser.home=/tmp',
'-Dspring.profiles.active=basicauth',
'-Dfile.encoding=UTF-8', '-Dfile.encoding=UTF-8',
'-Duser.timezone=UTC', '-Duser.timezone=UTC',
'-Djava.security.egd=file:/dev/./urandom' '-Djava.security.egd=file:/dev/./urandom'
@@ -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
@@ -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
@@ -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.service.TenantAwareJpaPlatformUserDetailsService;
import org.apache.fineract.infrastructure.security.vote.SelfServiceUserAccessVote; import org.apache.fineract.infrastructure.security.vote.SelfServiceUserAccessVote;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionManager; 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; import org.springframework.security.web.context.SecurityContextPersistenceFilter;
@Configuration @Configuration
@Profile("oauth") @ConditionalOnProperty("fineract.security.oauth.enabled")
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter { public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
@@ -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.filter.TwoFactorAuthenticationFilter;
import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService; import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 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; import org.springframework.security.web.context.SecurityContextPersistenceFilter;
@Configuration @Configuration
@Profile("basicauth") @ConditionalOnProperty("fineract.security.basicauth.enabled")
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@@ -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.");
}
}
}
@@ -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.constants.TwoFactorConstants;
import org.apache.fineract.infrastructure.security.data.AuthenticatedUserData; import org.apache.fineract.infrastructure.security.data.AuthenticatedUserData;
import org.apache.fineract.infrastructure.security.service.SpringSecurityPlatformSecurityContext; 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.portfolio.client.service.ClientReadPlatformService;
import org.apache.fineract.useradministration.data.RoleData; import org.apache.fineract.useradministration.data.RoleData;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.Role; import org.apache.fineract.useradministration.domain.Role;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; 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.context.annotation.Scope;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
@@ -61,11 +61,14 @@ import org.springframework.stereotype.Component;
@Component @Component
@Scope("singleton") @Scope("singleton")
@Profile("basicauth") @ConditionalOnProperty("fineract.security.basicauth.enabled")
@Path("/authentication") @Path("/authentication")
@Tag(name = "Authentication HTTP Basic", description = "An API capability that allows client applications to verify authentication details using HTTP Basic 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 { public class AuthenticationApiResource {
@Value("${fineract.security.2fa.enabled}")
private boolean twoFactorEnabled;
public static class AuthenticateRequest { public static class AuthenticateRequest {
public String username; public String username;
@@ -75,19 +78,17 @@ public class AuthenticationApiResource {
private final DaoAuthenticationProvider customAuthenticationProvider; private final DaoAuthenticationProvider customAuthenticationProvider;
private final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService; private final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService;
private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext; private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext;
private final TwoFactorUtils twoFactorUtils;
private final ClientReadPlatformService clientReadPlatformService; private final ClientReadPlatformService clientReadPlatformService;
@Autowired @Autowired
public AuthenticationApiResource( public AuthenticationApiResource(
@Qualifier("customAuthenticationProvider") final DaoAuthenticationProvider customAuthenticationProvider, @Qualifier("customAuthenticationProvider") final DaoAuthenticationProvider customAuthenticationProvider,
final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService, final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService,
final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext, TwoFactorUtils twoFactorUtils, final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext,
ClientReadPlatformService aClientReadPlatformService) { ClientReadPlatformService aClientReadPlatformService) {
this.customAuthenticationProvider = customAuthenticationProvider; this.customAuthenticationProvider = customAuthenticationProvider;
this.apiJsonSerializerService = apiJsonSerializerService; this.apiJsonSerializerService = apiJsonSerializerService;
this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext; this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext;
this.twoFactorUtils = twoFactorUtils;
clientReadPlatformService = aClientReadPlatformService; clientReadPlatformService = aClientReadPlatformService;
} }
@@ -143,7 +144,7 @@ public class AuthenticationApiResource {
final EnumOptionData organisationalRole = principal.organisationalRoleData(); final EnumOptionData organisationalRole = principal.organisationalRoleData();
boolean isTwoFactorRequired = twoFactorUtils.isTwoFactorAuthEnabled() boolean isTwoFactorRequired = this.twoFactorEnabled
&& !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION); && !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION);
Long userId = principal.getId(); Long userId = principal.getId();
if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) { if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) {
@@ -45,13 +45,13 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte
import org.apache.fineract.infrastructure.security.service.TwoFactorService; import org.apache.fineract.infrastructure.security.service.TwoFactorService;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; 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.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Path("/twofactor") @Path("/twofactor")
@Component @Component
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
@Scope("singleton") @Scope("singleton")
@Tag(name = "Two Factor", description = "") @Tag(name = "Two Factor", description = "")
public class TwoFactorApiResource { public class TwoFactorApiResource {
@@ -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.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.service.TwoFactorConfigurationService; import org.apache.fineract.infrastructure.security.service.TwoFactorConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; 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.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -42,7 +42,7 @@ import org.springframework.stereotype.Component;
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
@Component @Component
@Scope("singleton") @Scope("singleton")
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class TwoFactorConfigurationApiResource { public class TwoFactorConfigurationApiResource {
private final String resourceNameForPermissions = "TWOFACTOR_CONFIG"; private final String resourceNameForPermissions = "TWOFACTOR_CONFIG";
@@ -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.AuthenticatedOauthUserData;
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken; import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
import org.apache.fineract.infrastructure.security.service.SpringSecurityPlatformSecurityContext; 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.data.RoleData;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.Role; import org.apache.fineract.useradministration.domain.Role;
import org.springframework.beans.factory.annotation.Autowired; 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.context.annotation.Scope;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
@@ -54,22 +54,22 @@ import org.springframework.stereotype.Component;
*/ */
@Path("/userdetails") @Path("/userdetails")
@Component @Component
@Profile("oauth") @ConditionalOnProperty("fineract.security.oauth.enabled")
@Scope("singleton") @Scope("singleton")
@Tag(name = "Fetch authenticated user details", description = "") @Tag(name = "Fetch authenticated user details", description = "")
public class UserDetailsApiResource { public class UserDetailsApiResource {
private final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService; private final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService;
private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext; private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext;
private final TwoFactorUtils twoFactorUtils;
@Value("${fineract.security.2fa.enabled}")
private boolean twoFactorEnabled;
@Autowired @Autowired
public UserDetailsApiResource(final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService, public UserDetailsApiResource(final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService,
final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext, final TwoFactorUtils twoFactorUtils) { final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext) {
this.apiJsonSerializerService = apiJsonSerializerService; this.apiJsonSerializerService = apiJsonSerializerService;
this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext; this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext;
this.twoFactorUtils = twoFactorUtils;
} }
@GET @GET
@@ -116,16 +116,15 @@ public class UserDetailsApiResource {
final EnumOptionData organisationalRole = principal.organisationalRoleData(); final EnumOptionData organisationalRole = principal.organisationalRoleData();
final boolean requireTwoFactorAuth = twoFactorUtils.isTwoFactorAuthEnabled() boolean isTwoFactorRequired = this.twoFactorEnabled
&& !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION); && !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION);
if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) { if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) {
authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), principal.getId(), authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), principal.getId(),
authentication.getToken().getTokenValue(), requireTwoFactorAuth); authentication.getToken().getTokenValue(), isTwoFactorRequired);
} else { } else {
authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), officeId, officeName, staffId, staffDisplayName, authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), officeId, officeName, staffId, staffDisplayName,
organisationalRole, roles, permissions, principal.getId(), authentication.getToken().getTokenValue(), organisationalRole, roles, permissions, principal.getId(), authentication.getToken().getTokenValue(),
requireTwoFactorAuth); isTwoFactorRequired);
} }
return this.apiJsonSerializerService.serialize(authenticatedUserData); return this.apiJsonSerializerService.serialize(authenticatedUserData);
@@ -43,13 +43,13 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte
import org.apache.fineract.infrastructure.security.service.TwoFactorService; import org.apache.fineract.infrastructure.security.service.TwoFactorService;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@Service @Service
@CommandType(entity = "TWOFACTOR_ACCESSTOKEN", action = "INVALIDATE") @CommandType(entity = "TWOFACTOR_ACCESSTOKEN", action = "INVALIDATE")
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class InvalidateTFAccessTokenCommandHandler implements NewCommandSourceHandler { public class InvalidateTFAccessTokenCommandHandler implements NewCommandSourceHandler {
private final TwoFactorService twoFactorService; private final TwoFactorService twoFactorService;
@@ -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.data.TwoFactorConfigurationValidator;
import org.apache.fineract.infrastructure.security.service.TwoFactorConfigurationService; import org.apache.fineract.infrastructure.security.service.TwoFactorConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@Service @Service
@CommandType(entity = "TWOFACTOR_CONFIGURATION", action = "UPDATE") @CommandType(entity = "TWOFACTOR_CONFIGURATION", action = "UPDATE")
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class UpdateTwoFactorConfigCommandHandler implements NewCommandSourceHandler { public class UpdateTwoFactorConfigCommandHandler implements NewCommandSourceHandler {
private final TwoFactorConfigurationService configurationService; private final TwoFactorConfigurationService configurationService;
@@ -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.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.security.constants.TwoFactorConfigurationConstants; import org.apache.fineract.infrastructure.security.constants.TwoFactorConfigurationConstants;
import org.springframework.beans.factory.annotation.Autowired; 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; import org.springframework.stereotype.Component;
@Component @Component
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class TwoFactorConfigurationValidator { public class TwoFactorConfigurationValidator {
private final FromJsonHelper fromJsonHelper; private final FromJsonHelper fromJsonHelper;
@@ -21,12 +21,12 @@ package org.apache.fineract.infrastructure.security.domain;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.fineract.infrastructure.security.data.OTPRequest; import org.apache.fineract.infrastructure.security.data.OTPRequest;
import org.apache.fineract.useradministration.domain.AppUser; 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.stereotype.Repository;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@Repository @Repository
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
@SuppressWarnings({ "MemberName" }) @SuppressWarnings({ "MemberName" })
public class OTPRequestRepository { public class OTPRequestRepository {
@@ -19,11 +19,11 @@
package org.apache.fineract.infrastructure.security.domain; package org.apache.fineract.infrastructure.security.domain;
import org.apache.fineract.useradministration.domain.AppUser; 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.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public interface TFAccessTokenRepository extends JpaRepository<TFAccessToken, Long>, JpaSpecificationExecutor<TFAccessToken> { public interface TFAccessTokenRepository extends JpaRepository<TFAccessToken, Long>, JpaSpecificationExecutor<TFAccessToken> {
TFAccessToken findByUserAndToken(AppUser user, String token); TFAccessToken findByUserAndToken(AppUser user, String token);
@@ -19,11 +19,11 @@
package org.apache.fineract.infrastructure.security.domain; package org.apache.fineract.infrastructure.security.domain;
import java.util.List; 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.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public interface TwoFactorConfigurationRepository public interface TwoFactorConfigurationRepository
extends JpaRepository<TwoFactorConfiguration, Long>, JpaSpecificationExecutor<TwoFactorConfiguration> { extends JpaRepository<TwoFactorConfiguration, Long>, JpaSpecificationExecutor<TwoFactorConfiguration> {
@@ -27,7 +27,7 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken; 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.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; 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. * This filter adds 'TWOFACTOR_AUTHENTICATED' authority to every authenticated platform user.
*/ */
@Service @Service
@Profile("!twofactor") @ConditionalOnProperty(name = "fineract.security.2fa.enabled", havingValue = "false")
public class InsecureTwoFactorAuthenticationFilter extends TwoFactorAuthenticationFilter { public class InsecureTwoFactorAuthenticationFilter extends TwoFactorAuthenticationFilter {
public InsecureTwoFactorAuthenticationFilter() { public InsecureTwoFactorAuthenticationFilter() {
@@ -38,7 +38,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; 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.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication; 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. * 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 { public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFilter {
private static boolean firstRequestProcessed = false; private static boolean firstRequestProcessed = false;
@@ -38,7 +38,7 @@ import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetail
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; 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.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.filter.GenericFilterBean; 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. * Used to support Oauth2 authentication and the service is loaded only when "oauth" profile is active.
*/ */
@Service @Service
@Profile("oauth") @ConditionalOnProperty("fineract.security.oauth.enabled")
public class TenantAwareTenantIdentifierFilter extends GenericFilterBean { public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
private static boolean firstRequestProcessed = false; private static boolean firstRequestProcessed = false;
@@ -34,7 +34,7 @@ import org.apache.fineract.infrastructure.security.domain.TFAccessToken;
import org.apache.fineract.infrastructure.security.service.TwoFactorService; import org.apache.fineract.infrastructure.security.service.TwoFactorService;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; 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.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; 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. * authority regardless of the value of the 'Fineract-Platform-TFA-Token' header.
*/ */
@Service @Service
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class TwoFactorAuthenticationFilter extends GenericFilterBean { public class TwoFactorAuthenticationFilter extends GenericFilterBean {
private final TwoFactorService twoFactorService; private final TwoFactorService twoFactorService;
@@ -36,13 +36,13 @@ import org.apache.fineract.infrastructure.security.domain.TwoFactorConfiguration
import org.apache.fineract.infrastructure.security.domain.TwoFactorConfigurationRepository; import org.apache.fineract.infrastructure.security.domain.TwoFactorConfigurationRepository;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; 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.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class TwoFactorConfigurationServiceImpl implements TwoFactorConfigurationService { public class TwoFactorConfigurationServiceImpl implements TwoFactorConfigurationService {
private static final String DEFAULT_EMAIL_SUBJECT = "Fineract Two-Factor Authentication Token"; private static final String DEFAULT_EMAIL_SUBJECT = "Fineract Two-Factor Authentication Token";
@@ -39,14 +39,14 @@ import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
import org.apache.fineract.infrastructure.sms.scheduler.SmsMessageScheduledJobService; import org.apache.fineract.infrastructure.sms.scheduler.SmsMessageScheduledJobService;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; 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.CacheEvict;
import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@Profile("twofactor") @ConditionalOnProperty("fineract.security.2fa.enabled")
public class TwoFactorServiceImpl implements TwoFactorService { public class TwoFactorServiceImpl implements TwoFactorService {
private final AccessTokenGenerationService accessTokenGenerationService; private final AccessTokenGenerationService accessTokenGenerationService;
@@ -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;
}
}
@@ -31,13 +31,13 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.fineract.infrastructure.security.api.AuthenticationApiResource; import org.apache.fineract.infrastructure.security.api.AuthenticationApiResource;
import org.springframework.beans.factory.annotation.Autowired; 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.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Scope("singleton") @Scope("singleton")
@Profile("basicauth") @ConditionalOnProperty("fineract.security.basicauth.enabled")
@Path("/self/authentication") @Path("/self/authentication")
@Tag(name = "Self Authentication", description = "Authenticates the credentials provided and returns the set roles and permissions allowed") @Tag(name = "Self Authentication", description = "Authenticates the credentials provided and returns the set roles and permissions allowed")
public class SelfAuthenticationApiResource { public class SelfAuthenticationApiResource {
@@ -30,13 +30,13 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.fineract.infrastructure.security.api.UserDetailsApiResource; import org.apache.fineract.infrastructure.security.api.UserDetailsApiResource;
import org.springframework.beans.factory.annotation.Autowired; 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.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Path("/self/userdetails") @Path("/self/userdetails")
@Component @Component
@Profile("oauth") @ConditionalOnProperty("fineract.security.oauth.enabled")
@Scope("singleton") @Scope("singleton")
@Tag(name = "Self User Details", description = "") @Tag(name = "Self User Details", description = "")
@@ -17,8 +17,10 @@
# under the License. # under the License.
# #
spring.profiles.default=basicauth fineract.security.basicauth.enabled=${FINERACT_SECURITY_BASICAUTH_ENABLED:true}
spring.profiles.active=oauth,twofactor fineract.security.oauth.enabled=${FINERACT_SECURITY_OAUTH_ENABLED:false}
fineract.security.2fa.enabled=${FINERACT_SECURITY_2FA_ENABLED:false}
management.health.jms.enabled=false management.health.jms.enabled=false
# FINERACT 1296 # FINERACT 1296
@@ -34,4 +36,4 @@ management.endpoints.web.exposure.include=health,info
server.forward-headers-strategy=framework server.forward-headers-strategy=framework
# OAuth authorisation server endpoint # 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
@@ -29,14 +29,14 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; 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.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@TestPropertySource("classpath:application-test.properties")
@WebAppConfiguration @WebAppConfiguration
@ActiveProfiles("basicauth")
@ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class) @ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class)
public class CommandHandlerProviderTest { public class CommandHandlerProviderTest {
@@ -20,8 +20,8 @@ package org.apache.fineract.infrastructure.configuration.spring;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; 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.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration; 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). * sufficient (as long as the TestsWithoutDatabaseAndNoJobsConfiguration used extends AbstractApplicationConfiguration).
*/ */
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@TestPropertySource("classpath:application-test.properties")
@WebAppConfiguration @WebAppConfiguration
@ActiveProfiles("basicauth")
@ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class) @ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class)
public class SpringConfigurationTest { public class SpringConfigurationTest {
@@ -24,6 +24,9 @@ import org.apache.fineract.infrastructure.core.service.TenantDatabaseUpgradeServ
import org.apache.fineract.infrastructure.jobs.service.JobRegisterService; import org.apache.fineract.infrastructure.jobs.service.JobRegisterService;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.context.annotation.Bean; 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 * 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); DataSource mockDataSource = Mockito.mock(DataSource.class, Mockito.RETURNS_MOCKS);
return mockDataSource; return mockDataSource;
} }
@Bean
@Primary
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
} }
@@ -21,14 +21,14 @@ package org.apache.fineract.infrastructure.core.boot.tests;
import org.apache.fineract.ServerWithMariaDB4jApplication; import org.apache.fineract.ServerWithMariaDB4jApplication;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest; 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.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@SpringBootTest(classes = ServerWithMariaDB4jApplication.Configuration.class) @SpringBootTest(classes = ServerWithMariaDB4jApplication.Configuration.class)
@TestPropertySource("classpath:application-test.properties")
@WebAppConfiguration @WebAppConfiguration
@ActiveProfiles("basicauth")
public abstract class AbstractSpringBootWithMariaDB4jIntegrationTest { public abstract class AbstractSpringBootWithMariaDB4jIntegrationTest {
// do NOT put any helper methods here! // do NOT put any helper methods here!
@@ -17,7 +17,10 @@
# under the License. # 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 management.health.jms.enabled=false
# FINERACT 1296 # FINERACT 1296
+1 -1
View File
@@ -45,7 +45,7 @@ cargo {
} }
startStopTimeout = 240000 startStopTimeout = 240000
containerProperties { 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.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks")
property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.connector.keystorePass', 'openmf'
property 'cargo.tomcat.httpSecure', true property 'cargo.tomcat.httpSecure', true
+1 -1
View File
@@ -45,7 +45,7 @@ cargo {
} }
startStopTimeout = 240000 startStopTimeout = 240000
containerProperties { 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.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks")
property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.connector.keystorePass', 'openmf'
property 'cargo.tomcat.httpSecure', true property 'cargo.tomcat.httpSecure', true
@@ -111,7 +111,7 @@ public class TwoFactorAuthenticationTest {
.log().ifError().when().post("/fineract-provider/api/v1/authentication?" + TENANT_IDENTIFIER).asString(); .log().ifError().when().post("/fineract-provider/api/v1/authentication?" + TENANT_IDENTIFIER).asString();
assertFalse(StringUtils.isBlank(json)); assertFalse(StringUtils.isBlank(json));
Boolean key = JsonPath.with(json).get("isTwoFactorAuthenticationRequired"); Boolean key = JsonPath.with(json).get("isTwoFactorAuthenticationRequired");
assertEquals(key, true); assertEquals(true, key);
} }
@Test @Test