Skip to content

Commit

Permalink
#25636 added config property to match saml config id to a site (#25762)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsolistorres committed Aug 16, 2023
1 parent 86db9de commit 9163cef
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.dotcms.saml;

import com.dotcms.security.apps.AppSecrets;
import com.dotcms.security.apps.AppsAPI;
import com.dotcms.security.apps.Secret;
import com.dotcms.security.apps.Type;
import com.dotcms.util.IntegrationTestInitService;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.beans.Host;
import com.dotmarketing.portlets.contentlet.business.HostAPI;
import com.dotmarketing.util.Config;
import org.apache.felix.framework.OSGIUtil;
Expand All @@ -11,10 +14,11 @@
import org.junit.Test;

import java.security.UnrecoverableKeyException;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static org.mockito.Matchers.anyCollection;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand All @@ -37,10 +41,46 @@ public void test_UnrecoverableKeyException() {
final HostAPI hostAPI = mock(HostAPI.class);

when(appsAPI.filterSitesForAppKey(anyString(),
anyCollection(), anyObject())).thenThrow(new RuntimeException(new UnrecoverableKeyException()));
anyCollection(), any())).thenThrow(new RuntimeException(new UnrecoverableKeyException()));
final IdentityProviderConfigurationFactory configurationFactory = new DotIdentityProviderConfigurationFactoryImpl(appsAPI, hostAPI);
final IdentityProviderConfiguration identityProviderConfiguration = configurationFactory.findIdentityProviderConfigurationById("xxx");

Assert.assertNull(identityProviderConfiguration);
}

@Test
public void test_findIdentityProviderConfigurationByConfigId() throws Exception {

final AppsAPI appsAPI = mock(AppsAPI.class);
final HostAPI hostAPI = mock(HostAPI.class);

Config.setProperty("dotcms.saml.use.idp.config.id", true);

final String testConfigId = "792c699b-5025-4869-9ae8-2ff78f245fe9";

when(appsAPI.filterSitesForAppKey(anyString(),
anyCollection(), any())).thenReturn(Set.of());

final String testHostId = "5b54cc87-eab8-466b-814a-a621adf695d8";
final Map<String, Set<String>> keysByHost = Map.of(testHostId,
Set.of(DotSamlProxyFactory.SAML_APP_CONFIG_KEY));
when(appsAPI.appKeysByHost()).thenReturn(keysByHost);

final Host testHost = mock(Host.class);
when(testHost.getIdentifier()).thenReturn(testHostId);
when(hostAPI.find(anyString(), any(), anyBoolean())).thenReturn(testHost);

final AppSecrets appSecrets = mock(AppSecrets.class);
when(appSecrets.getSecrets()).thenReturn(Map.of("idp.config.identifier",
Secret.newSecret(testConfigId.toCharArray(), Type.STRING, false)));
when(appsAPI.getSecrets(anyString(), any(), any())).thenReturn(Optional.of(appSecrets));
when(appsAPI.getSecrets(anyString(), anyBoolean(), any(), any())).thenReturn(Optional.of(appSecrets));

final IdentityProviderConfigurationFactory configurationFactory =
new DotIdentityProviderConfigurationFactoryImpl(appsAPI, hostAPI);
final IdentityProviderConfiguration identityProviderConfiguration =
configurationFactory.findIdentityProviderConfigurationById(testConfigId);

Assert.assertNotNull(identityProviderConfiguration);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
package com.dotcms.saml;

import com.dotcms.security.apps.AppSecrets;
import com.dotcms.security.apps.AppsAPI;
import com.dotcms.security.apps.Secret;
import com.dotmarketing.beans.Host;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.portlets.contentlet.business.HostAPI;
import com.dotmarketing.util.Config;
import io.vavr.control.Try;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* DotCMS implementation for the {@link IdentityProviderConfigurationFactory}
* @author jsanca
*/
public class DotIdentityProviderConfigurationFactoryImpl implements IdentityProviderConfigurationFactory {

private static final String DOTCMS_SAML_USE_IDP_CONFIG_ID = "dotcms.saml.use.idp.config.id";
private static final String IDP_CONFIG_IDENTIFIER = "idp.config.identifier";

private final AppsAPI appsAPI;
private final HostAPI hostAPI;

Expand All @@ -28,24 +37,72 @@ public DotIdentityProviderConfigurationFactoryImpl(final AppsAPI appsAPI, final
public IdentityProviderConfiguration findIdentityProviderConfigurationById(
final String identityProviderIdentifier) {

return this.existsConfiguration(identityProviderIdentifier)?
this.createIdentityProviderConfigurationFor(identityProviderIdentifier): null;
IdentityProviderConfiguration identityProviderConfiguration =
this.existsConfigurationForSite(identityProviderIdentifier)?
this.createIdentityProviderConfigurationForSite(identityProviderIdentifier): null;

// if the configuration is not found for the site, then try to find it by config id
// when the flag to find by config id is enabled
if (null == identityProviderConfiguration &&
Config.getBooleanProperty(DOTCMS_SAML_USE_IDP_CONFIG_ID, false)) {
identityProviderConfiguration =
this.createIdentityProviderConfigurationForConfigId(identityProviderIdentifier);
}

return identityProviderConfiguration;
}

private boolean existsConfiguration(final String identityProviderIdentifier) {
private boolean existsConfigurationForSite(final String identityProviderIdentifier) {

final List hosts = Host.SYSTEM_HOST.equals(identityProviderIdentifier)?
Arrays.asList(identityProviderIdentifier): Arrays.asList(Host.SYSTEM_HOST, identityProviderIdentifier);
final List<String> hosts = Host.SYSTEM_HOST.equals(identityProviderIdentifier)?
List.of(identityProviderIdentifier) : Arrays.asList(Host.SYSTEM_HOST, identityProviderIdentifier);

return Try.of(()->!this.appsAPI.filterSitesForAppKey(DotSamlProxyFactory.SAML_APP_CONFIG_KEY,
hosts, APILocator.systemUser()).isEmpty()).getOrElse(false);
}

private IdentityProviderConfiguration createIdentityProviderConfigurationFor(final String identityProviderIdentifier) {
private IdentityProviderConfiguration createIdentityProviderConfigurationForSite(final String identityProviderIdentifier) {

final Host host = Try.of(()->
hostAPI.find(identityProviderIdentifier, APILocator.systemUser(), false)).getOrNull();

return null != host?Try.of(()->new DotIdentityProviderConfigurationImpl(this.appsAPI, host)).getOrNull():null;
}

private IdentityProviderConfiguration createIdentityProviderConfigurationForConfigId(
final String identityProviderIdentifier) {

final List<Host> sites = Try.of(()-> this.appsAPI.appKeysByHost().entrySet().stream()
.filter(entry -> entry.getValue().contains(DotSamlProxyFactory.SAML_APP_CONFIG_KEY))
.map(entry ->
Try.of(()-> hostAPI.find(
entry.getKey(), APILocator.systemUser(), false)).getOrNull())
.filter(Objects::nonNull)
.collect(Collectors.toList())).getOrElse(List.of());

final Host siteWithConfigId = sites.stream()
.filter(host -> {
final Optional<AppSecrets> appSecretsOptional = Try.of(() ->
this.appsAPI.getSecrets(DotSamlProxyFactory.SAML_APP_CONFIG_KEY,
host, APILocator.systemUser())).getOrElse(Optional.empty());
if (appSecretsOptional.isPresent()) {
final AppSecrets appSecrets = appSecretsOptional.get();
if (appSecrets.getSecrets().containsKey(IDP_CONFIG_IDENTIFIER)) {
final Optional<Secret> secretOptional = Optional.ofNullable(
appSecrets.getSecrets().get(IDP_CONFIG_IDENTIFIER));
return secretOptional.isPresent() &&
secretOptional.get().getString().equals(identityProviderIdentifier);
}
}
return false;
}).findFirst().orElse(null);

if (null == siteWithConfigId) {
return null;
}

return Try.of(() ->
new DotIdentityProviderConfigurationImpl(this.appsAPI, siteWithConfigId)).getOrNull();
}

}

0 comments on commit 9163cef

Please sign in to comment.