From e7e5d30b3538ce6aed22cd020a22f3bffe4b52bc Mon Sep 17 00:00:00 2001 From: ImalshaG Date: Thu, 25 Apr 2024 23:38:19 +0530 Subject: [PATCH] Provide API support to configure fido trusted origins --- .../fido2/core/WebAuthnService.java | 79 ++++++++++++++----- .../util/FIDO2AuthenticatorConstants.java | 2 + .../fido2/core/WebAuthnServiceTest.java | 8 +- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnService.java b/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnService.java index 5181ce85..6f548bb0 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnService.java +++ b/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnService.java @@ -143,6 +143,8 @@ import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_MDS_VALIDATION_ATTRIBUTE_NAME; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_MDS_VALIDATION_DEFAULT_VALUE; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_RESOURCE_NAME; +import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME; +import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONNECTOR_CONFIG_RESOURCE_NAME; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_USER; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO_CONFIG_RESOURCE_TYPE_NAME; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIRST_NAME_CLAIM_URL; @@ -992,32 +994,40 @@ private User getPrivilegedUser() { private void readTrustedOrigins() { - if (origins == null) { - origins = new ArrayList<>(); + origins = new ArrayList<>(); + String[] trustedOriginsFromDB = null; + try { + trustedOriginsFromDB = getFIDO2TrustedOrigins(); + } catch (FIDO2AuthenticatorServerException e) { + log.error("Error when retrieving FIDO trusted origins from DB. Using the default values from files."); + } + if (trustedOriginsFromDB != null) { + origins.addAll(Arrays.asList(trustedOriginsFromDB)); + } else { Object value = IdentityConfigParser.getInstance().getConfiguration().get(TRUSTED_ORIGINS); if (value instanceof ArrayList) { origins.addAll((ArrayList) value); } else if (value instanceof String) { origins.add((String) value); } - origins.replaceAll(IdentityUtil::fillURLPlaceholders); - - /* - * Process the list of origins to ensure all variations are covered: - * 1. For each origin, remove the default ports (443 for HTTPS and 80 for HTTP) if they are explicitly - * specified. - * 2. Then, for each origin, add variations with the default ports explicitly appended. - * 3. This ensures that the list contains both versions of each origin (with and without default ports), - * accommodating scenarios where the default port might be omitted or explicitly included in the origin - * string. - */ - List updatedOrigins = origins.stream() - .flatMap(url -> Stream.of(removeDefaultPort(url), appendDefaultPortIfAbsent(url))).distinct() - .collect(Collectors.toList()); - - origins.clear(); - origins.addAll(updatedOrigins); } + origins.replaceAll(IdentityUtil::fillURLPlaceholders); + + /* + * Process the list of origins to ensure all variations are covered: + * 1. For each origin, remove the default ports (443 for HTTPS and 80 for HTTP) if they are explicitly + * specified. + * 2. Then, for each origin, add variations with the default ports explicitly appended. + * 3. This ensures that the list contains both versions of each origin (with and without default ports), + * accommodating scenarios where the default port might be omitted or explicitly included in the origin + * string. + */ + List updatedOrigins = origins.stream() + .flatMap(url -> Stream.of(removeDefaultPort(url), appendDefaultPortIfAbsent(url))).distinct() + .collect(Collectors.toList()); + + origins.clear(); + origins.addAll(updatedOrigins); } private String removeDefaultPort(String url) { @@ -1271,6 +1281,37 @@ private FIDO2Configuration getAuthenticatorConfigs() throws FIDO2AuthenticatorSe return new FIDO2Configuration(attestationValidationEnabled, mdsValidationEnabled); } + private String[] getFIDO2TrustedOrigins() throws FIDO2AuthenticatorServerException { + + String[] fidoTrustedOrigins = null; + try { + fidoTrustedOrigins = FIDO2AuthenticatorServiceDataHolder.getInstance().getConfigurationManager() + .getAttribute(FIDO_CONFIG_RESOURCE_TYPE_NAME, FIDO2_CONNECTOR_CONFIG_RESOURCE_NAME, + FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME).getValue().split(","); + } catch (ConfigurationManagementException e) { + if (Objects.equals(e.getErrorCode(), ERROR_CODE_ATTRIBUTE_DOES_NOT_EXISTS.getCode())) { + if (log.isDebugEnabled()) { + log.debug(FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME + + " attribute doesn't exist for the tenant: " + + PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId() + + ". Using the default configuration value from files."); + } + } else if (Objects.equals(e.getErrorCode(), ERROR_CODE_RESOURCE_DOES_NOT_EXISTS.getCode())) { + if (log.isDebugEnabled()) { + log.debug(FIDO2_CONNECTOR_CONFIG_RESOURCE_NAME + " resource doesn't exist for the tenant: " + + PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId() + + ". Using the default configuration value from files for the attribute: " + + FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME + "."); + } + } else { + throw new FIDO2AuthenticatorServerException("Error in retrieving " + + FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME + " configuration for the tenant: " + + PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(), e); + } + } + return fidoTrustedOrigins; + } + public boolean isFidoKeyRegistered (String username) throws AuthenticationFailedException { try { return !userStorage.getFIDO2RegistrationsByUsername(username).isEmpty(); diff --git a/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/util/FIDO2AuthenticatorConstants.java b/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/util/FIDO2AuthenticatorConstants.java index 66b10113..6359308b 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/util/FIDO2AuthenticatorConstants.java +++ b/components/org.wso2.carbon.identity.application.authenticator.fido2/src/main/java/org/wso2/carbon/identity/application/authenticator/fido2/util/FIDO2AuthenticatorConstants.java @@ -62,10 +62,12 @@ private FIDO2AuthenticatorConstants() { public static final String FIDO_CONFIG_RESOURCE_TYPE_NAME = "fido-config"; public static final String FIDO2_CONFIG_RESOURCE_NAME = "fido2-validations"; + public static final String FIDO2_CONNECTOR_CONFIG_RESOURCE_NAME = "fido-connector"; public static final String FIDO2_CONFIG_ATTESTATION_VALIDATION_ATTRIBUTE_NAME = "AttestationValidation.Enable"; public static final boolean FIDO2_CONFIG_ATTESTATION_VALIDATION_DEFAULT_VALUE = true; public static final String FIDO2_CONFIG_MDS_VALIDATION_ATTRIBUTE_NAME = "MDSValidation.Enable"; public static final boolean FIDO2_CONFIG_MDS_VALIDATION_DEFAULT_VALUE = false; + public static final String FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME = "FIDO2TrustedOrigins"; /** * SQL Queries class for FIDO2 Authenticator Constants Util class. diff --git a/components/org.wso2.carbon.identity.application.authenticator.fido2/src/test/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnServiceTest.java b/components/org.wso2.carbon.identity.application.authenticator.fido2/src/test/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnServiceTest.java index 012aadf9..7da55651 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.fido2/src/test/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnServiceTest.java +++ b/components/org.wso2.carbon.identity.application.authenticator.fido2/src/test/java/org/wso2/carbon/identity/application/authenticator/fido2/core/WebAuthnServiceTest.java @@ -81,6 +81,7 @@ import org.wso2.carbon.identity.application.authenticator.fido2.util.FIDOUtil; import org.wso2.carbon.identity.application.common.model.User; import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager; +import org.wso2.carbon.identity.configuration.mgt.core.exception.ConfigurationManagementException; import org.wso2.carbon.identity.configuration.mgt.core.model.Attribute; import org.wso2.carbon.identity.core.util.IdentityConfigParser; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; @@ -121,8 +122,10 @@ import static org.powermock.api.mockito.PowerMockito.whenNew; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_ATTESTATION_VALIDATION_ATTRIBUTE_NAME; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_MDS_VALIDATION_ATTRIBUTE_NAME; +import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONFIG_RESOURCE_NAME; import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO_CONFIG_RESOURCE_TYPE_NAME; +import static org.wso2.carbon.identity.application.authenticator.fido2.util.FIDO2AuthenticatorConstants.FIDO2_CONNECTOR_CONFIG_RESOURCE_NAME; import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_ID; @@ -214,7 +217,7 @@ public class WebAuthnServiceTest { private AssertionResult assertionResult; @BeforeMethod - public void setUp() throws UserStoreException, IOException, FIDO2AuthenticatorServerException { + public void setUp() throws UserStoreException, IOException, FIDO2AuthenticatorServerException, ConfigurationManagementException { prepareResources(); initMocks(this); @@ -230,6 +233,9 @@ public void setUp() throws UserStoreException, IOException, FIDO2AuthenticatorSe when(FIDO2DeviceStoreDAO.getInstance()).thenReturn(fido2DeviceStoreDAO); trustedOrigins.add(ORIGIN); identityConfig.put(FIDO2AuthenticatorConstants.TRUSTED_ORIGINS, trustedOrigins); + when(configurationManager.getAttribute(FIDO_CONFIG_RESOURCE_TYPE_NAME, FIDO2_CONNECTOR_CONFIG_RESOURCE_NAME, + FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME)).thenReturn( + new Attribute(FIDO2_CONFIG_TRUSTED_ORIGIN_ATTRIBUTE_NAME, (String.join(",",trustedOrigins)))); mockStatic(IdentityConfigParser.class); when(IdentityConfigParser.getInstance()).thenReturn(identityConfigParser); when(identityConfigParser.getConfiguration()).thenReturn(identityConfig);