You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2023/03/31 11:20:56 UTC

[syncope] branch 3_0_X updated: Refactor WA mapper management (#433)

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

ilgrosso pushed a commit to branch 3_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/3_0_X by this push:
     new 29d2934856 Refactor WA mapper management (#433)
29d2934856 is described below

commit 29d2934856019c5b5a157cc7d672347a1f190283
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Fri Mar 31 13:20:49 2023 +0200

    Refactor WA mapper management (#433)
---
 .../src/main/resources/wa-embedded.properties      |  3 +
 pom.xml                                            |  4 +-
 .../syncope/wa/starter/config/WAContext.java       | 64 ++++---------------
 .../syncope/wa/starter/mapping/AccessMapFor.java   | 32 ----------
 .../syncope/wa/starter/mapping/AccessMapper.java   |  4 +-
 .../wa/starter/mapping/AttrReleaseMapFor.java      | 32 ----------
 .../wa/starter/mapping/AttrReleaseMapper.java      |  4 +-
 .../syncope/wa/starter/mapping/AuthMapFor.java     | 32 ----------
 .../syncope/wa/starter/mapping/AuthMapper.java     |  4 +-
 .../wa/starter/mapping/AuthMapperResult.java       |  2 +
 .../wa/starter/mapping/CASSPClientAppTOMapper.java |  7 ++-
 .../wa/starter/mapping/ClientAppMapFor.java        | 32 ----------
 .../wa/starter/mapping/ClientAppMapper.java        |  4 +-
 .../wa/starter/mapping/DefaultAccessMapper.java    |  7 ++-
 .../starter/mapping/DefaultAttrReleaseMapper.java  |  7 ++-
 .../wa/starter/mapping/DefaultAuthMapper.java      |  7 ++-
 .../mapping/DefaultTicketExpirationMapper.java     |  7 ++-
 .../starter/mapping/HttpRequestAccessMapper.java   |  7 ++-
 .../starter/mapping/OIDCRPClientAppTOMapper.java   |  7 ++-
 .../starter/mapping/RegisteredServiceMapper.java   | 72 +++++++++++-----------
 .../mapping/RemoteEndpointAccessMapper.java        |  7 ++-
 .../starter/mapping/SAML2SPClientAppTOMapper.java  |  7 ++-
 .../wa/starter/mapping/TicketExpirationMapFor.java | 32 ----------
 .../wa/starter/mapping/TicketExpirationMapper.java |  3 +
 .../wa/starter/mapping/TimeBasedAccessMapper.java  |  7 ++-
 .../wa/starter/services/WAServiceRegistry.java     |  2 +
 26 files changed, 132 insertions(+), 264 deletions(-)

diff --git a/fit/wa-reference/src/main/resources/wa-embedded.properties b/fit/wa-reference/src/main/resources/wa-embedded.properties
index f050292fa7..641378b141 100644
--- a/fit/wa-reference/src/main/resources/wa-embedded.properties
+++ b/fit/wa-reference/src/main/resources/wa-embedded.properties
@@ -23,6 +23,9 @@ keymaster.password=${anonymousKey}
 cas.server.name=https://localhost:9443
 cas.server.prefix=${cas.server.name}/syncope-wa
 
+cas.authn.syncope.url=${cas.server.name}/syncope
+cas.authn.syncope.name=DefaultSyncopeAuthModule
+
 service.discovery.address=https://localhost:9443/syncope-wa/
 
 ##
diff --git a/pom.xml b/pom.xml
index eff6e1a121..1c03eae921 100644
--- a/pom.xml
+++ b/pom.xml
@@ -430,7 +430,7 @@ under the License.
 
     <slf4j.version>1.7.36</slf4j.version>
 
-    <elasticsearch.version>8.6.2</elasticsearch.version>
+    <elasticsearch.version>8.7.0</elasticsearch.version>
 
     <log4j2.version>2.19.0</log4j2.version>
     <disruptor.version>3.4.4</disruptor.version>
@@ -441,7 +441,7 @@ under the License.
 
     <pac4j.version>5.5.0</pac4j.version>
 
-    <cas.version>6.6.7-SNAPSHOT</cas.version>
+    <cas.version>6.6.7</cas.version>
     <cas-client.version>3.6.4</cas-client.version>
 
     <h2.version>2.1.214</h2.version>
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java
index c8c946b8d4..e14d0dd9a6 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java
@@ -28,9 +28,7 @@ import io.swagger.v3.oas.models.info.Info;
 import io.swagger.v3.oas.models.security.SecurityScheme;
 import java.time.OffsetDateTime;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
@@ -44,14 +42,10 @@ import org.apache.syncope.wa.starter.audit.WAAuditTrailManager;
 import org.apache.syncope.wa.starter.events.WAEventRepository;
 import org.apache.syncope.wa.starter.gauth.WAGoogleMfaAuthCredentialRepository;
 import org.apache.syncope.wa.starter.gauth.WAGoogleMfaAuthTokenRepository;
-import org.apache.syncope.wa.starter.mapping.AccessMapFor;
 import org.apache.syncope.wa.starter.mapping.AccessMapper;
-import org.apache.syncope.wa.starter.mapping.AttrReleaseMapFor;
 import org.apache.syncope.wa.starter.mapping.AttrReleaseMapper;
-import org.apache.syncope.wa.starter.mapping.AuthMapFor;
 import org.apache.syncope.wa.starter.mapping.AuthMapper;
 import org.apache.syncope.wa.starter.mapping.CASSPClientAppTOMapper;
-import org.apache.syncope.wa.starter.mapping.ClientAppMapFor;
 import org.apache.syncope.wa.starter.mapping.ClientAppMapper;
 import org.apache.syncope.wa.starter.mapping.DefaultAccessMapper;
 import org.apache.syncope.wa.starter.mapping.DefaultAttrReleaseMapper;
@@ -62,7 +56,6 @@ import org.apache.syncope.wa.starter.mapping.OIDCRPClientAppTOMapper;
 import org.apache.syncope.wa.starter.mapping.RegisteredServiceMapper;
 import org.apache.syncope.wa.starter.mapping.RemoteEndpointAccessMapper;
 import org.apache.syncope.wa.starter.mapping.SAML2SPClientAppTOMapper;
-import org.apache.syncope.wa.starter.mapping.TicketExpirationMapFor;
 import org.apache.syncope.wa.starter.mapping.TicketExpirationMapper;
 import org.apache.syncope.wa.starter.mapping.TimeBasedAccessMapper;
 import org.apache.syncope.wa.starter.oidc.WAOIDCJWKSGeneratorService;
@@ -205,58 +198,23 @@ public class WAContext {
     public RegisteredServiceMapper registeredServiceMapper(
             final ConfigurableApplicationContext ctx,
             final CasConfigurationProperties casProperties,
-            final ObjectProvider<AuthenticationEventExecutionPlan> authenticationEventExecutionPlan) {
-
-        Map<String, AuthMapper> authPolicyConfMappers = new HashMap<>();
-        ctx.getBeansOfType(AuthMapper.class).forEach((name, bean) -> {
-            AuthMapFor amf = ctx.findAnnotationOnBean(name, AuthMapFor.class);
-            if (amf != null) {
-                authPolicyConfMappers.put(amf.authPolicyConfClass().getName(), bean);
-            }
-        });
-
-        Map<String, AccessMapper> accessPolicyConfMappers = new HashMap<>();
-        ctx.getBeansOfType(AccessMapper.class).forEach((name, bean) -> {
-            AccessMapFor amf = ctx.findAnnotationOnBean(name, AccessMapFor.class);
-            if (amf != null) {
-                accessPolicyConfMappers.put(amf.accessPolicyConfClass().getName(), bean);
-            }
-        });
-
-        Map<String, AttrReleaseMapper> attrReleasePolicyConfMappers = new HashMap<>();
-        ctx.getBeansOfType(AttrReleaseMapper.class).forEach((name, bean) -> {
-            AttrReleaseMapFor armpf = ctx.findAnnotationOnBean(name, AttrReleaseMapFor.class);
-            if (armpf != null) {
-                attrReleasePolicyConfMappers.put(armpf.attrReleasePolicyConfClass().getName(), bean);
-            }
-        });
-
-        Map<String, TicketExpirationMapper> ticketExpirationPolicyConfMappers = new HashMap<>();
-        ctx.getBeansOfType(TicketExpirationMapper.class).forEach((name, bean) -> {
-            TicketExpirationMapFor temf = ctx.findAnnotationOnBean(name, TicketExpirationMapFor.class);
-            if (temf != null) {
-                ticketExpirationPolicyConfMappers.put(temf.ticketExpirationPolicyConfClass().getName(), bean);
-            }
-        });
-
-        Map<String, ClientAppMapper> clientAppTOMappers = new HashMap<>();
-        ctx.getBeansOfType(ClientAppMapper.class).forEach((name, bean) -> {
-            ClientAppMapFor clientAppMapFor = ctx.findAnnotationOnBean(name, ClientAppMapFor.class);
-            if (clientAppMapFor != null) {
-                clientAppTOMappers.put(clientAppMapFor.clientAppClass().getName(), bean);
-            }
-        });
+            final ObjectProvider<AuthenticationEventExecutionPlan> authenticationEventExecutionPlan,
+            final List<AuthMapper> authMappers,
+            final List<AccessMapper> accessMappers,
+            final List<AttrReleaseMapper> attrReleaseMappers,
+            final List<TicketExpirationMapper> ticketExpirationMappers,
+            final List<ClientAppMapper> clientAppMappers) {
 
         return new RegisteredServiceMapper(
                 ctx,
                 Optional.ofNullable(casProperties.getAuthn().getPac4j().getCore().getName()).
                         orElse(DelegatedClientAuthenticationHandler.class.getSimpleName()),
                 authenticationEventExecutionPlan,
-                authPolicyConfMappers,
-                accessPolicyConfMappers,
-                attrReleasePolicyConfMappers,
-                ticketExpirationPolicyConfMappers,
-                clientAppTOMappers);
+                authMappers,
+                accessMappers,
+                attrReleaseMappers,
+                ticketExpirationMappers,
+                clientAppMappers);
     }
 
     @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapFor.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapFor.java
deleted file mode 100644
index 9ed2543288..0000000000
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapFor.java
+++ /dev/null
@@ -1,32 +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.syncope.wa.starter.mapping;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import org.apache.syncope.common.lib.policy.AccessPolicyConf;
-
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface AccessMapFor {
-
-    Class<? extends AccessPolicyConf> accessPolicyConfClass();
-}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapper.java
index b6240cfc09..e5878a96e6 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapper.java
@@ -18,11 +18,13 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
+import org.apache.syncope.common.lib.policy.AccessPolicyConf;
 import org.apache.syncope.common.lib.policy.AccessPolicyTO;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 
-@FunctionalInterface
 public interface AccessMapper {
 
+    boolean supports(AccessPolicyConf conf);
+
     RegisteredServiceAccessStrategy build(AccessPolicyTO policy);
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapFor.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapFor.java
deleted file mode 100644
index f28390dce8..0000000000
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapFor.java
+++ /dev/null
@@ -1,32 +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.syncope.wa.starter.mapping;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf;
-
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface AttrReleaseMapFor {
-
-    Class<? extends AttrReleasePolicyConf> attrReleasePolicyConfClass();
-}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java
index 8a63943fac..7b54d36734 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java
@@ -18,11 +18,13 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
+import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf;
 import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO;
 import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
 
-@FunctionalInterface
 public interface AttrReleaseMapper {
 
+    boolean supports(AttrReleasePolicyConf conf);
+
     RegisteredServiceAttributeReleasePolicy build(AttrReleasePolicyTO policy);
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapFor.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapFor.java
deleted file mode 100644
index f5fb5e4a06..0000000000
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapFor.java
+++ /dev/null
@@ -1,32 +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.syncope.wa.starter.mapping;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import org.apache.syncope.common.lib.policy.AuthPolicyConf;
-
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface AuthMapFor {
-
-    Class<? extends AuthPolicyConf> authPolicyConfClass();
-}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapper.java
index 7c0c1ab62d..d2f3f23e02 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapper.java
@@ -19,15 +19,17 @@
 package org.apache.syncope.wa.starter.mapping;
 
 import java.util.List;
+import org.apache.syncope.common.lib.policy.AuthPolicyConf;
 import org.apache.syncope.common.lib.policy.AuthPolicyTO;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
 import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
 import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.context.ConfigurableApplicationContext;
 
-@FunctionalInterface
 public interface AuthMapper {
 
+    boolean supports(AuthPolicyConf conf);
+
     AuthMapperResult build(
             ConfigurableApplicationContext ctx,
             String pac4jCoreName,
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapperResult.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapperResult.java
index cdb2440537..018d1a6eda 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapperResult.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AuthMapperResult.java
@@ -24,6 +24,8 @@ import org.apereo.cas.services.RegisteredServiceMultifactorPolicy;
 
 public class AuthMapperResult {
 
+    public static final AuthMapperResult EMPTY = new AuthMapperResult(null, null, null);
+
     private final RegisteredServiceAuthenticationPolicy authPolicy;
 
     private final RegisteredServiceMultifactorPolicy mfaPolicy;
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPClientAppTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPClientAppTOMapper.java
index a3a4bd70e7..8294aed3a0 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPClientAppTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPClientAppTOMapper.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.wa.starter.mapping;
 
 import org.apache.syncope.common.lib.to.CASSPClientAppTO;
+import org.apache.syncope.common.lib.to.ClientAppTO;
 import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apereo.cas.services.CasRegisteredService;
 import org.apereo.cas.services.RegisteredService;
@@ -32,9 +33,13 @@ import org.apereo.cas.services.RegisteredServiceServiceTicketExpirationPolicy;
 import org.apereo.cas.services.RegisteredServiceTicketGrantingTicketExpirationPolicy;
 import org.springframework.context.ConfigurableApplicationContext;
 
-@ClientAppMapFor(clientAppClass = CASSPClientAppTO.class)
 public class CASSPClientAppTOMapper extends AbstractClientAppMapper {
 
+    @Override
+    public boolean supports(final ClientAppTO clientApp) {
+        return clientApp instanceof CASSPClientAppTO;
+    }
+
     @Override
     public RegisteredService map(
             final ConfigurableApplicationContext ctx,
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapFor.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapFor.java
deleted file mode 100644
index 5bd1b07358..0000000000
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapFor.java
+++ /dev/null
@@ -1,32 +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.syncope.wa.starter.mapping;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import org.apache.syncope.common.lib.to.ClientAppTO;
-
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ClientAppMapFor {
-
-    Class<? extends ClientAppTO> clientAppClass();
-}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java
index d3d0010b0b..5dd8e7c9bb 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
+import org.apache.syncope.common.lib.to.ClientAppTO;
 import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
@@ -30,9 +31,10 @@ import org.apereo.cas.services.RegisteredServiceServiceTicketExpirationPolicy;
 import org.apereo.cas.services.RegisteredServiceTicketGrantingTicketExpirationPolicy;
 import org.springframework.context.ConfigurableApplicationContext;
 
-@FunctionalInterface
 public interface ClientAppMapper {
 
+    boolean supports(ClientAppTO clientApp);
+
     RegisteredService map(
             ConfigurableApplicationContext ctx,
             WAClientApp clientApp,
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java
index aef2e4ee59..be4a7f13d5 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java
@@ -21,14 +21,19 @@ package org.apache.syncope.wa.starter.mapping;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.policy.AccessPolicyConf;
 import org.apache.syncope.common.lib.policy.AccessPolicyTO;
 import org.apache.syncope.common.lib.policy.DefaultAccessPolicyConf;
 import org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 
-@AccessMapFor(accessPolicyConfClass = DefaultAccessPolicyConf.class)
 public class DefaultAccessMapper implements AccessMapper {
 
+    @Override
+    public boolean supports(final AccessPolicyConf conf) {
+        return conf instanceof DefaultAccessPolicyConf;
+    }
+
     @Override
     public RegisteredServiceAccessStrategy build(final AccessPolicyTO policy) {
         DefaultAccessPolicyConf conf = (DefaultAccessPolicyConf) policy.getConf();
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java
index ecca60f82c..d3f982a2f2 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.wa.starter.mapping;
 
 import java.util.HashSet;
+import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf;
 import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO;
 import org.apache.syncope.common.lib.policy.DefaultAttrReleasePolicyConf;
 import org.apereo.cas.authentication.principal.DefaultPrincipalAttributesRepository;
@@ -34,9 +35,13 @@ import org.apereo.cas.services.ReturnMappedAttributeReleasePolicy;
 import org.apereo.cas.services.consent.DefaultRegisteredServiceConsentPolicy;
 import org.apereo.cas.util.model.TriStateBoolean;
 
-@AttrReleaseMapFor(attrReleasePolicyConfClass = DefaultAttrReleasePolicyConf.class)
 public class DefaultAttrReleaseMapper implements AttrReleaseMapper {
 
+    @Override
+    public boolean supports(final AttrReleasePolicyConf conf) {
+        return conf instanceof DefaultAttrReleasePolicyConf;
+    }
+
     @Override
     public RegisteredServiceAttributeReleasePolicy build(final AttrReleasePolicyTO policy) {
         DefaultAttrReleasePolicyConf conf = (DefaultAttrReleasePolicyConf) policy.getConf();
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
index 351ef87159..3094dd27f8 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.auth.MFAAuthModuleConf;
 import org.apache.syncope.common.lib.auth.Pac4jAuthModuleConf;
+import org.apache.syncope.common.lib.policy.AuthPolicyConf;
 import org.apache.syncope.common.lib.policy.AuthPolicyTO;
 import org.apache.syncope.common.lib.policy.DefaultAuthPolicyConf;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
@@ -42,11 +43,15 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.context.ConfigurableApplicationContext;
 
-@AuthMapFor(authPolicyConfClass = DefaultAuthPolicyConf.class)
 public class DefaultAuthMapper implements AuthMapper {
 
     protected static final Logger LOG = LoggerFactory.getLogger(DefaultAuthMapper.class);
 
+    @Override
+    public boolean supports(final AuthPolicyConf conf) {
+        return conf instanceof DefaultAuthPolicyConf;
+    }
+
     @Override
     public AuthMapperResult build(
             final ConfigurableApplicationContext ctx,
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultTicketExpirationMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultTicketExpirationMapper.java
index 5a0a3ec4b1..2a2f74cf86 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultTicketExpirationMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultTicketExpirationMapper.java
@@ -20,6 +20,7 @@ package org.apache.syncope.wa.starter.mapping;
 
 import java.util.Optional;
 import org.apache.syncope.common.lib.policy.DefaultTicketExpirationPolicyConf;
+import org.apache.syncope.common.lib.policy.TicketExpirationPolicyConf;
 import org.apache.syncope.common.lib.policy.TicketExpirationPolicyTO;
 import org.apereo.cas.services.DefaultRegisteredServiceProxyGrantingTicketExpirationPolicy;
 import org.apereo.cas.services.DefaultRegisteredServiceProxyTicketExpirationPolicy;
@@ -30,9 +31,13 @@ import org.apereo.cas.services.RegisteredServiceProxyTicketExpirationPolicy;
 import org.apereo.cas.services.RegisteredServiceServiceTicketExpirationPolicy;
 import org.apereo.cas.services.RegisteredServiceTicketGrantingTicketExpirationPolicy;
 
-@TicketExpirationMapFor(ticketExpirationPolicyConfClass = DefaultTicketExpirationPolicyConf.class)
 public class DefaultTicketExpirationMapper implements TicketExpirationMapper {
 
+    @Override
+    public boolean supports(final TicketExpirationPolicyConf conf) {
+        return conf instanceof DefaultTicketExpirationPolicyConf;
+    }
+
     protected Optional<DefaultTicketExpirationPolicyConf> conf(final TicketExpirationPolicyTO policy) {
         if (policy.getConf() instanceof DefaultTicketExpirationPolicyConf) {
             return Optional.of((DefaultTicketExpirationPolicyConf) policy.getConf());
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/HttpRequestAccessMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/HttpRequestAccessMapper.java
index ea034f1586..7e3cf71cce 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/HttpRequestAccessMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/HttpRequestAccessMapper.java
@@ -19,14 +19,19 @@
 package org.apache.syncope.wa.starter.mapping;
 
 import java.util.Optional;
+import org.apache.syncope.common.lib.policy.AccessPolicyConf;
 import org.apache.syncope.common.lib.policy.AccessPolicyTO;
 import org.apache.syncope.common.lib.policy.HttpRequestAccessPolicyConf;
 import org.apereo.cas.services.HttpRequestRegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 
-@AccessMapFor(accessPolicyConfClass = HttpRequestAccessPolicyConf.class)
 public class HttpRequestAccessMapper implements AccessMapper {
 
+    @Override
+    public boolean supports(final AccessPolicyConf conf) {
+        return conf instanceof HttpRequestAccessPolicyConf;
+    }
+
     @Override
     public RegisteredServiceAccessStrategy build(final AccessPolicyTO policy) {
         HttpRequestAccessPolicyConf conf = (HttpRequestAccessPolicyConf) policy.getConf();
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java
index 654c33f5a4..421faf9a66 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java
@@ -24,6 +24,7 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.apache.syncope.common.lib.to.ClientAppTO;
 import org.apache.syncope.common.lib.to.OIDCRPClientAppTO;
 import org.apache.syncope.common.lib.types.OIDCGrantType;
 import org.apache.syncope.common.lib.types.OIDCResponseType;
@@ -51,11 +52,15 @@ import org.apereo.cas.services.RegisteredServiceTicketGrantingTicketExpirationPo
 import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy;
 import org.springframework.context.ConfigurableApplicationContext;
 
-@ClientAppMapFor(clientAppClass = OIDCRPClientAppTO.class)
 public class OIDCRPClientAppTOMapper extends AbstractClientAppMapper {
 
     private static final String CUSTOM_SCOPE = "syncope";
 
+    @Override
+    public boolean supports(final ClientAppTO clientApp) {
+        return clientApp instanceof OIDCRPClientAppTO;
+    }
+
     @Override
     public RegisteredService map(
             final ConfigurableApplicationContext ctx,
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java
index b0a9fd8cf6..f58104134f 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
-import java.util.Map;
+import java.util.List;
 import java.util.Optional;
 import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO;
 import org.apache.syncope.common.lib.policy.DefaultAttrReleasePolicyConf;
@@ -50,41 +50,43 @@ public class RegisteredServiceMapper {
 
     protected final ObjectProvider<AuthenticationEventExecutionPlan> authEventExecPlan;
 
-    protected final Map<String, AuthMapper> authPolicyConfMappers;
+    protected final List<AuthMapper> authMappers;
 
-    protected final Map<String, AccessMapper> accessPolicyConfMappers;
+    protected final List<AccessMapper> accessMappers;
 
-    protected final Map<String, AttrReleaseMapper> attrReleasePolicyConfMappers;
+    protected final List<AttrReleaseMapper> attrReleaseMappers;
 
-    protected final Map<String, TicketExpirationMapper> ticketExpirationPolicyConfMappers;
+    protected final List<TicketExpirationMapper> ticketExpirationMappers;
 
-    protected final Map<String, ClientAppMapper> clientAppTOMappers;
+    protected final List<ClientAppMapper> clientAppMappers;
 
     public RegisteredServiceMapper(
             final ConfigurableApplicationContext ctx,
             final String pac4jCoreName,
             final ObjectProvider<AuthenticationEventExecutionPlan> authEventExecPlan,
-            final Map<String, AuthMapper> authPolicyConfMappers,
-            final Map<String, AccessMapper> accessPolicyConfMappers,
-            final Map<String, AttrReleaseMapper> attrReleasePolicyConfMappers,
-            final Map<String, TicketExpirationMapper> ticketExpirationPolicyConfMappers,
-            final Map<String, ClientAppMapper> clientAppTOMappers) {
+            final List<AuthMapper> authMappers,
+            final List<AccessMapper> accessMappers,
+            final List<AttrReleaseMapper> attrReleaseMappers,
+            final List<TicketExpirationMapper> ticketExpirationMappers,
+            final List<ClientAppMapper> clientAppMappers) {
 
         this.ctx = ctx;
         this.pac4jCoreName = pac4jCoreName;
         this.authEventExecPlan = authEventExecPlan;
-        this.authPolicyConfMappers = authPolicyConfMappers;
-        this.accessPolicyConfMappers = accessPolicyConfMappers;
-        this.attrReleasePolicyConfMappers = attrReleasePolicyConfMappers;
-        this.ticketExpirationPolicyConfMappers = ticketExpirationPolicyConfMappers;
-        this.clientAppTOMappers = clientAppTOMappers;
+        this.authMappers = authMappers;
+        this.accessMappers = accessMappers;
+        this.attrReleaseMappers = attrReleaseMappers;
+        this.ticketExpirationMappers = ticketExpirationMappers;
+        this.clientAppMappers = clientAppMappers;
     }
 
     public RegisteredService toRegisteredService(final WAClientApp clientApp) {
-        String key = clientApp.getClientAppTO().getClass().getName();
-        ClientAppMapper clientAppMapper = clientAppTOMappers.get(key);
+        ClientAppMapper clientAppMapper = clientAppMappers.stream().
+                filter(m -> m.supports(clientApp.getClientAppTO())).
+                findFirst().
+                orElse(null);
         if (clientAppMapper == null) {
-            LOG.warn("Unable to locate ClientAppMapper using key {}", key);
+            LOG.warn("Unable to locate ClientAppMapper for {}", clientApp.getClientAppTO().getClass().getName());
             return null;
         }
 
@@ -92,11 +94,12 @@ public class RegisteredServiceMapper {
         RegisteredServiceMultifactorPolicy mfaPolicy = null;
         RegisteredServiceDelegatedAuthenticationPolicy delegatedAuthPolicy = null;
         if (clientApp.getAuthPolicy() != null) {
-            AuthMapper authMapper = authPolicyConfMappers.get(
-                    clientApp.getAuthPolicy().getConf().getClass().getName());
-            AuthMapperResult result = Optional.ofNullable(authMapper).map(mapper -> mapper.build(
+            Optional<AuthMapper> authMapper = authMappers.stream().
+                    filter(m -> m.supports(clientApp.getAuthPolicy().getConf())).
+                    findFirst();
+            AuthMapperResult result = authMapper.map(mapper -> mapper.build(
                     ctx, pac4jCoreName, authEventExecPlan, clientApp.getAuthPolicy(), clientApp.getAuthModules())).
-                    orElseGet(() -> new AuthMapperResult(null, null, null));
+                    orElse(AuthMapperResult.EMPTY);
             authPolicy = result.getAuthPolicy();
             mfaPolicy = result.getMfaPolicy();
             delegatedAuthPolicy = result.getDelegateAuthPolicy();
@@ -104,11 +107,10 @@ public class RegisteredServiceMapper {
 
         RegisteredServiceAccessStrategy accessStrategy = null;
         if (clientApp.getAccessPolicy() != null) {
-            AccessMapper accessPolicyConfMapper = accessPolicyConfMappers.get(
-                    clientApp.getAccessPolicy().getConf().getClass().getName());
-            accessStrategy = Optional.ofNullable(accessPolicyConfMapper).
-                    map(mapper -> mapper.build(clientApp.getAccessPolicy())).
-                    orElse(null);
+            Optional<AccessMapper> accessMapper = accessMappers.stream().
+                    filter(m -> m.supports(clientApp.getAccessPolicy().getConf())).
+                    findFirst();
+            accessStrategy = accessMapper.map(mapper -> mapper.build(clientApp.getAccessPolicy())).orElse(null);
         }
         if (delegatedAuthPolicy != null) {
             if (accessStrategy == null) {
@@ -129,20 +131,20 @@ public class RegisteredServiceMapper {
                     arpTO.setConf(new DefaultAttrReleasePolicyConf());
                     return arpTO;
                 });
-        AttrReleaseMapper attrReleasePolicyConfMapper = attrReleasePolicyConfMappers.get(
-                attrReleasePolicyTO.getConf().getClass().getName());
+        Optional<AttrReleaseMapper> attrReleaseMapper = attrReleaseMappers.stream().
+                filter(m -> m.supports(attrReleasePolicyTO.getConf())).
+                findFirst();
         RegisteredServiceAttributeReleasePolicy attributeReleasePolicy =
-                Optional.ofNullable(attrReleasePolicyConfMapper).
-                        map(mapper -> mapper.build(attrReleasePolicyTO)).
-                        orElse(null);
+                attrReleaseMapper.map(mapper -> mapper.build(attrReleasePolicyTO)).orElse(null);
 
         RegisteredServiceTicketGrantingTicketExpirationPolicy tgtExpirationPolicy = null;
         RegisteredServiceServiceTicketExpirationPolicy stExpirationPolicy = null;
         RegisteredServiceProxyGrantingTicketExpirationPolicy tgtProxyExpirationPolicy = null;
         RegisteredServiceProxyTicketExpirationPolicy stProxyExpirationPolicy = null;
         if (clientApp.getTicketExpirationPolicy() != null) {
-            TicketExpirationMapper ticketExpirationMapper = ticketExpirationPolicyConfMappers.get(
-                    clientApp.getTicketExpirationPolicy().getConf().getClass().getName());
+            TicketExpirationMapper ticketExpirationMapper = ticketExpirationMappers.stream().
+                    filter(m -> m.supports(clientApp.getTicketExpirationPolicy().getConf())).
+                    findFirst().orElse(null);
             if (ticketExpirationMapper != null) {
                 tgtExpirationPolicy = ticketExpirationMapper.buildTGT(clientApp.getTicketExpirationPolicy());
                 stExpirationPolicy = ticketExpirationMapper.buildST(clientApp.getTicketExpirationPolicy());
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RemoteEndpointAccessMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RemoteEndpointAccessMapper.java
index 595a593039..0f46aba479 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RemoteEndpointAccessMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RemoteEndpointAccessMapper.java
@@ -19,14 +19,19 @@
 package org.apache.syncope.wa.starter.mapping;
 
 import java.util.Optional;
+import org.apache.syncope.common.lib.policy.AccessPolicyConf;
 import org.apache.syncope.common.lib.policy.AccessPolicyTO;
 import org.apache.syncope.common.lib.policy.RemoteEndpointAccessPolicyConf;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RemoteEndpointServiceAccessStrategy;
 
-@AccessMapFor(accessPolicyConfClass = RemoteEndpointAccessPolicyConf.class)
 public class RemoteEndpointAccessMapper implements AccessMapper {
 
+    @Override
+    public boolean supports(final AccessPolicyConf conf) {
+        return conf instanceof RemoteEndpointAccessPolicyConf;
+    }
+
     @Override
     public RegisteredServiceAccessStrategy build(final AccessPolicyTO policy) {
         RemoteEndpointAccessPolicyConf conf = (RemoteEndpointAccessPolicyConf) policy.getConf();
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPClientAppTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPClientAppTOMapper.java
index 51eaebb333..2aa6375b46 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPClientAppTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPClientAppTOMapper.java
@@ -20,6 +20,7 @@ package org.apache.syncope.wa.starter.mapping;
 
 import java.util.Optional;
 import java.util.stream.Collectors;
+import org.apache.syncope.common.lib.to.ClientAppTO;
 import org.apache.syncope.common.lib.to.SAML2SPClientAppTO;
 import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apereo.cas.services.RegisteredService;
@@ -35,9 +36,13 @@ import org.apereo.cas.support.saml.services.SamlRegisteredService;
 import org.apereo.cas.util.model.TriStateBoolean;
 import org.springframework.context.ConfigurableApplicationContext;
 
-@ClientAppMapFor(clientAppClass = SAML2SPClientAppTO.class)
 public class SAML2SPClientAppTOMapper extends AbstractClientAppMapper {
 
+    @Override
+    public boolean supports(final ClientAppTO clientApp) {
+        return clientApp instanceof SAML2SPClientAppTO;
+    }
+
     @Override
     public RegisteredService map(
             final ConfigurableApplicationContext ctx,
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapFor.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapFor.java
deleted file mode 100644
index b13b2fe106..0000000000
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapFor.java
+++ /dev/null
@@ -1,32 +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.syncope.wa.starter.mapping;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import org.apache.syncope.common.lib.policy.TicketExpirationPolicyConf;
-
-@Target({ ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface TicketExpirationMapFor {
-
-    Class<? extends TicketExpirationPolicyConf> ticketExpirationPolicyConfClass();
-}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapper.java
index fc040b0a86..618873a376 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TicketExpirationMapper.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
+import org.apache.syncope.common.lib.policy.TicketExpirationPolicyConf;
 import org.apache.syncope.common.lib.policy.TicketExpirationPolicyTO;
 import org.apereo.cas.services.RegisteredServiceProxyGrantingTicketExpirationPolicy;
 import org.apereo.cas.services.RegisteredServiceProxyTicketExpirationPolicy;
@@ -26,6 +27,8 @@ import org.apereo.cas.services.RegisteredServiceTicketGrantingTicketExpirationPo
 
 public interface TicketExpirationMapper {
 
+    boolean supports(TicketExpirationPolicyConf conf);
+
     RegisteredServiceTicketGrantingTicketExpirationPolicy buildTGT(TicketExpirationPolicyTO policy);
 
     RegisteredServiceServiceTicketExpirationPolicy buildST(TicketExpirationPolicyTO policy);
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TimeBasedAccessMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TimeBasedAccessMapper.java
index f4cd0f2e34..9cb0f3deae 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TimeBasedAccessMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/TimeBasedAccessMapper.java
@@ -20,14 +20,19 @@ package org.apache.syncope.wa.starter.mapping;
 
 import java.time.format.DateTimeFormatter;
 import java.util.Optional;
+import org.apache.syncope.common.lib.policy.AccessPolicyConf;
 import org.apache.syncope.common.lib.policy.AccessPolicyTO;
 import org.apache.syncope.common.lib.policy.TimeBasedAccessPolicyConf;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.TimeBasedRegisteredServiceAccessStrategy;
 
-@AccessMapFor(accessPolicyConfClass = TimeBasedAccessPolicyConf.class)
 public class TimeBasedAccessMapper implements AccessMapper {
 
+    @Override
+    public boolean supports(final AccessPolicyConf conf) {
+        return conf instanceof TimeBasedAccessPolicyConf;
+    }
+
     @Override
     public RegisteredServiceAccessStrategy build(final AccessPolicyTO policy) {
         TimeBasedAccessPolicyConf conf = (TimeBasedAccessPolicyConf) policy.getConf();
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/services/WAServiceRegistry.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/services/WAServiceRegistry.java
index 29665b7afe..a6a2e9843d 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/services/WAServiceRegistry.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/services/WAServiceRegistry.java
@@ -20,6 +20,7 @@ package org.apache.syncope.wa.starter.services;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import org.apache.syncope.client.lib.SyncopeClient;
@@ -80,6 +81,7 @@ public class WAServiceRegistry extends AbstractServiceRegistry {
             LOG.info("Loading application definitions");
             return waRestClient.getSyncopeClient().getService(WAClientAppService.class).list().stream().
                     map(registeredServiceMapper::toRegisteredService).
+                    filter(Objects::nonNull).
                     collect(Collectors.toList());
         }
     }