You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by mm...@apache.org on 2020/07/03 17:45:22 UTC

[syncope] branch master updated: Upgrade WA to 6.3.0 (#200)

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

mmoayyed pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new 708c9cb  Upgrade WA to 6.3.0 (#200)
708c9cb is described below

commit 708c9cb8b54d876592105b114b46814771a4b152
Author: Misagh Moayyed <mm...@gmail.com>
AuthorDate: Fri Jul 3 22:15:14 2020 +0430

    Upgrade WA to 6.3.0 (#200)
    
    * switch WA to 6.3 SNAPSHOT; fix APIs
    
    * upgrade yo CAS 6.3; rework gauth account management
    
    * upgrade to CAS 6.3; rework gauth account management
    
    * fix tests and permission issue
    
    * fix test
    
    * fix api return types for collections
    
    Co-authored-by: Francesco Chicchiriccò <il...@users.noreply.github.com>
---
 .../syncope/common/lib/types/AMEntitlement.java    |   2 +
 .../common/lib/types/GoogleMfaAuthAccount.java     |  36 +++++++
 .../service/wa/GoogleMfaAuthAccountService.java    |  20 +++-
 .../core/logic/GoogleMfaAuthAccountLogic.java      |  91 ++++++++++++----
 .../wa/GoogleMfaAuthAccountServiceImpl.java        |  30 ++++--
 .../persistence/api/dao/auth/AuthProfileDAO.java   |   2 +
 .../persistence/api/entity/auth/AuthProfile.java   |   6 +-
 .../jpa/dao/auth/JPAAuthProfileDAO.java            |   7 ++
 .../jpa/entity/auth/JPAAuthProfile.java            |  22 ++--
 .../persistence/jpa/inner/AuthProfileTest.java     |  33 +++---
 .../fit/core/GoogleMfaAuthAccountITCase.java       |  19 ++--
 pom.xml                                            |   2 +-
 .../bootstrap/SyncopeWAPropertySourceLocator.java  |   2 +-
 .../wa/starter/config/SyncopeWAConfiguration.java  |   6 +-
 ...SyncopeWAGoogleMfaAuthCredentialRepository.java | 116 ++++++++++++++++-----
 .../apache/syncope/wa/starter/AbstractTest.java    |   1 +
 .../wa/starter/SyncopeWAServiceRegistryTest.java   |   6 +-
 17 files changed, 304 insertions(+), 97 deletions(-)

diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
index 6e2ccaa..ca78af3 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
@@ -96,6 +96,8 @@ public final class AMEntitlement {
 
     public static final String GOOGLE_MFA_COUNT_ACCOUNTS = "GOOGLE_MFA_COUNT_ACCOUNTS";
 
+    public static final String GOOGLE_MFA_LIST_ACCOUNTS = "GOOGLE_MFA_LIST_ACCOUNTS";
+
     public static final String OIDC_JWKS_CREATE = "OIDC_JWKS_CREATE";
 
     public static final String OIDC_JWKS_READ = "OIDC_JWKS_READ";
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GoogleMfaAuthAccount.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GoogleMfaAuthAccount.java
index d5c9c89..17cbef9 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GoogleMfaAuthAccount.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GoogleMfaAuthAccount.java
@@ -36,8 +36,12 @@ public class GoogleMfaAuthAccount implements BaseBean {
 
     private String secretKey;
 
+    private String name;
+
     private int validationCode;
 
+    private long id;
+
     private List<Integer> scratchCodes = new ArrayList<>(0);
 
     private String owner;
@@ -52,6 +56,22 @@ public class GoogleMfaAuthAccount implements BaseBean {
         this.key = key;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(final long id) {
+        this.id = id;
+    }
+
     public String getOwner() {
         return owner;
     }
@@ -101,6 +121,8 @@ public class GoogleMfaAuthAccount implements BaseBean {
             .append(key)
             .append(secretKey)
             .append(owner)
+            .append(name)
+            .append(id)
             .append(scratchCodes)
             .append(validationCode)
             .append(registrationDate)
@@ -124,6 +146,8 @@ public class GoogleMfaAuthAccount implements BaseBean {
             .append(this.key, rhs.key)
             .append(this.secretKey, rhs.secretKey)
             .append(this.owner, rhs.owner)
+            .append(this.name, rhs.name)
+            .append(this.id, rhs.id)
             .append(this.scratchCodes, rhs.scratchCodes)
             .append(this.registrationDate, rhs.registrationDate)
             .append(this.validationCode, rhs.validationCode)
@@ -134,8 +158,10 @@ public class GoogleMfaAuthAccount implements BaseBean {
     public String toString() {
         return new ToStringBuilder(this)
             .append("key", key)
+            .append("name", name)
             .append("secretKey", secretKey)
             .append("owner", owner)
+            .append("id", id)
             .append("scratchCodes", scratchCodes)
             .append("registrationDate", registrationDate)
             .append("validationCode", validationCode)
@@ -166,11 +192,21 @@ public class GoogleMfaAuthAccount implements BaseBean {
             return this;
         }
 
+        public GoogleMfaAuthAccount.Builder id(final Long id) {
+            instance.setId(id);
+            return this;
+        }
+
         public GoogleMfaAuthAccount.Builder owner(final String owner) {
             instance.setOwner(owner);
             return this;
         }
 
+        public GoogleMfaAuthAccount.Builder name(final String name) {
+            instance.setName(name);
+            return this;
+        }
+
         public GoogleMfaAuthAccount.Builder key(final String key) {
             instance.setKey(key);
             return this;
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java
index 27338b1..3dbac81 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java
@@ -43,6 +43,8 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import java.util.List;
+
 @Tag(name = "Google MFA Accounts")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
@@ -54,7 +56,7 @@ public interface GoogleMfaAuthAccountService extends JAXRSService {
     @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Path("accts/owners/${owner}")
-    Response deleteAccountFor(@NotNull @PathParam("owner") String owner);
+    Response deleteAccountsFor(@NotNull @PathParam("owner") String owner);
 
     @DELETE
     @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
@@ -90,7 +92,7 @@ public interface GoogleMfaAuthAccountService extends JAXRSService {
     @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Path("accts/owners/${owner}")
-    GoogleMfaAuthAccount findAccountFor(@NotNull @PathParam("owner") String owner);
+    List<GoogleMfaAuthAccount> findAccountsFor(@NotNull @PathParam("owner") String owner);
 
     @GET
     @Path("accts/{key}")
@@ -99,6 +101,12 @@ public interface GoogleMfaAuthAccountService extends JAXRSService {
     GoogleMfaAuthAccount findAccountBy(@NotNull @PathParam("key") String key);
 
     @GET
+    @Path("accts/id/{id}")
+    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    GoogleMfaAuthAccount findAccountBy(@NotNull @PathParam("id") long id);
+
+    @GET
     @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Path("accts/count")
@@ -107,6 +115,12 @@ public interface GoogleMfaAuthAccountService extends JAXRSService {
     @GET
     @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Path("accts/count/{owner}")
+    PagedResult<GoogleMfaAuthAccount> countFor(@NotNull @PathParam("owner") String owner);
+
+    @GET
+    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
     @Path("accts")
-    PagedResult<GoogleMfaAuthAccount> list();
+    List<GoogleMfaAuthAccount> list();
 }
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/GoogleMfaAuthAccountLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/GoogleMfaAuthAccountLogic.java
index 1ba9274..b799695 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/GoogleMfaAuthAccountLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/GoogleMfaAuthAccountLogic.java
@@ -80,9 +80,9 @@ public class GoogleMfaAuthAccountLogic extends AbstractTransactionalLogic<AuthPr
 
     @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_DELETE_ACCOUNT + "') "
         + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    public void deleteAccountFor(final String owner) {
+    public void deleteAccountsFor(final String owner) {
         authProfileDAO.findByOwner(owner).ifPresent(profile -> {
-            profile.setGoogleMfaAuthAccount(null);
+            profile.setGoogleMfaAuthAccounts(List.of());
             authProfileDAO.save(profile);
         });
     }
@@ -92,7 +92,7 @@ public class GoogleMfaAuthAccountLogic extends AbstractTransactionalLogic<AuthPr
     public void deleteAll() {
         authProfileDAO.findAll().
             forEach(profile -> {
-                profile.setGoogleMfaAuthAccount(null);
+                profile.setGoogleMfaAuthAccounts(List.of());
                 authProfileDAO.save(profile);
             });
     }
@@ -110,26 +110,36 @@ public class GoogleMfaAuthAccountLogic extends AbstractTransactionalLogic<AuthPr
         if (acct.getKey() == null) {
             acct.setKey(SecureRandomUtils.generateRandomUUID().toString());
         }
-        profile.setGoogleMfaAuthAccount(acct);
-        return authProfileDAO.save(profile).getGoogleMfaAuthAccount();
+        profile.add(acct);
+        profile = authProfileDAO.save(profile);
+        return profile.getGoogleMfaAuthAccounts().
+            stream().
+            filter(t -> t.getKey().equals(acct.getKey())).
+            findFirst().
+            orElse(null);
     }
 
     @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_UPDATE_ACCOUNT + "') "
         + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    public void update(final GoogleMfaAuthAccount acct) {
-        AuthProfile profile = authProfileDAO.findByOwner(acct.getOwner()).
-            orElseThrow(() -> new NotFoundException("Could not find account for Owner " + acct.getOwner()));
-        profile.setGoogleMfaAuthAccount(acct);
-        authProfileDAO.save(profile).getGoogleMfaAuthAccount();
+    public void update(final GoogleMfaAuthAccount account) {
+        AuthProfile authProfile = authProfileDAO.findByOwner(account.getOwner()).
+            orElseThrow(() -> new NotFoundException("Could not find account for Owner " + account.getOwner()));
+        final List<GoogleMfaAuthAccount> accounts = authProfile.getGoogleMfaAuthAccounts();
+        if (accounts.removeIf(acct -> acct.getKey().equals(account.getKey()))) {
+            accounts.add(account);
+            authProfile.setGoogleMfaAuthAccounts(accounts);
+            authProfileDAO.save(authProfile);
+        }
     }
 
     @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_READ_ACCOUNT + "') "
         + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    public GoogleMfaAuthAccount findAccountFor(final String owner) {
+    public List<GoogleMfaAuthAccount> findAccountsFor(final String owner) {
         return authProfileDAO.findByOwner(owner).
             stream().
-            map(AuthProfile::getGoogleMfaAuthAccount).
+            map(AuthProfile::getGoogleMfaAuthAccounts).
             filter(Objects::nonNull).
+            filter(accounts -> !accounts.isEmpty()).
             findFirst().
             orElseThrow(() -> new NotFoundException("Could not find account for Owner " + owner));
     }
@@ -140,9 +150,30 @@ public class GoogleMfaAuthAccountLogic extends AbstractTransactionalLogic<AuthPr
     public GoogleMfaAuthAccount findAccountBy(final String key) {
         return authProfileDAO.findAll().
             stream().
-            map(AuthProfile::getGoogleMfaAuthAccount).
+            map(AuthProfile::getGoogleMfaAuthAccounts).
+            filter(Objects::nonNull).
+            map(accounts -> accounts.stream().
+                filter(acct -> acct.getKey().equals(key)).
+                findFirst().
+                orElse(null)).
+            filter(Objects::nonNull).
+            findFirst().
+            orElse(null);
+    }
+
+    @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_READ_ACCOUNT + "') "
+        + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    @Transactional(readOnly = true)
+    public GoogleMfaAuthAccount findAccountBy(final long id) {
+        return authProfileDAO.findAll().
+            stream().
+            map(AuthProfile::getGoogleMfaAuthAccounts).
+            filter(Objects::nonNull).
+            map(accounts -> accounts.stream().
+                filter(acct -> acct.getId() == id).
+                findFirst().
+                orElse(null)).
             filter(Objects::nonNull).
-            filter(acct -> acct.getKey().equals(key)).
             findFirst().
             orElse(null);
     }
@@ -152,8 +183,19 @@ public class GoogleMfaAuthAccountLogic extends AbstractTransactionalLogic<AuthPr
     public long countAll() {
         return authProfileDAO.findAll().
             stream().
-            filter(profile -> profile.getGoogleMfaAuthAccount() != null).
-            count();
+            filter(profile -> profile.getGoogleMfaAuthAccounts() != null).
+            mapToInt(profile -> profile.getGoogleMfaAuthAccounts().size()).
+            sum();
+    }
+
+    @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_COUNT_ACCOUNTS + "') "
+        + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    public long countFor(final String owner) {
+        return authProfileDAO.findByOwner(owner).
+            stream().
+            filter(profile -> profile.getGoogleMfaAuthAccounts() != null).
+            mapToInt(profile -> profile.getGoogleMfaAuthAccounts().size()).
+            sum();
     }
 
     @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_DELETE_ACCOUNT + "') "
@@ -161,22 +203,27 @@ public class GoogleMfaAuthAccountLogic extends AbstractTransactionalLogic<AuthPr
     public void deleteAccountBy(final String key) {
         authProfileDAO.findAll().
             stream().
-            filter(profile -> profile.getGoogleMfaAuthAccount() != null
-                && profile.getGoogleMfaAuthAccount().getKey().equals(key)).
+            filter(profile -> profile.getGoogleMfaAuthAccounts() != null
+                && profile.getGoogleMfaAuthAccounts().stream().anyMatch(acct -> acct.getKey().equals(key))).
             findFirst().
             ifPresent(profile -> {
-                profile.setGoogleMfaAuthAccount(null);
-                authProfileDAO.save(profile);
+                List<GoogleMfaAuthAccount> accounts = profile.getGoogleMfaAuthAccounts();
+                boolean removed = accounts.removeIf(acct -> acct.getKey().equals(key));
+                if (removed) {
+                    authProfileDAO.save(profile);
+                }
             });
     }
 
-    @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    @PreAuthorize("hasRole('" + AMEntitlement.GOOGLE_MFA_LIST_ACCOUNTS + "') "
+        + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
     @Transactional(readOnly = true)
     public List<GoogleMfaAuthAccount> list() {
         return authProfileDAO.findAll().
             stream().
-            map(AuthProfile::getGoogleMfaAuthAccount).
+            map(AuthProfile::getGoogleMfaAuthAccounts).
             filter(Objects::nonNull).
+            flatMap(List::stream).
             collect(Collectors.toList());
     }
 }
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/GoogleMfaAuthAccountServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/GoogleMfaAuthAccountServiceImpl.java
index 38a43d2..44d1578 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/GoogleMfaAuthAccountServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/GoogleMfaAuthAccountServiceImpl.java
@@ -31,6 +31,7 @@ import org.springframework.stereotype.Service;
 import javax.ws.rs.core.Response;
 
 import java.net.URI;
+import java.util.List;
 
 @Service
 public class GoogleMfaAuthAccountServiceImpl extends AbstractServiceImpl implements GoogleMfaAuthAccountService {
@@ -38,8 +39,8 @@ public class GoogleMfaAuthAccountServiceImpl extends AbstractServiceImpl impleme
     private GoogleMfaAuthAccountLogic logic;
 
     @Override
-    public Response deleteAccountFor(final String owner) {
-        logic.deleteAccountFor(owner);
+    public Response deleteAccountsFor(final String owner) {
+        logic.deleteAccountsFor(owner);
         return Response.noContent().build();
     }
 
@@ -57,10 +58,10 @@ public class GoogleMfaAuthAccountServiceImpl extends AbstractServiceImpl impleme
 
     @Override
     public Response save(final GoogleMfaAuthAccount acct) {
-        final GoogleMfaAuthAccount token = logic.save(acct);
-        URI location = uriInfo.getAbsolutePathBuilder().path(token.getKey()).build();
+        final GoogleMfaAuthAccount account = logic.save(acct);
+        URI location = uriInfo.getAbsolutePathBuilder().path(account.getKey()).build();
         return Response.created(location).
-            header(RESTHeaders.RESOURCE_KEY, token.getKey()).
+            header(RESTHeaders.RESOURCE_KEY, account.getKey()).
             build();
     }
 
@@ -70,8 +71,8 @@ public class GoogleMfaAuthAccountServiceImpl extends AbstractServiceImpl impleme
     }
 
     @Override
-    public GoogleMfaAuthAccount findAccountFor(final String owner) {
-        return logic.findAccountFor(owner);
+    public List<GoogleMfaAuthAccount> findAccountsFor(final String owner) {
+        return logic.findAccountsFor(owner);
     }
 
     @Override
@@ -80,6 +81,11 @@ public class GoogleMfaAuthAccountServiceImpl extends AbstractServiceImpl impleme
     }
 
     @Override
+    public GoogleMfaAuthAccount findAccountBy(final long id) {
+        return logic.findAccountBy(id);
+    }
+
+    @Override
     public PagedResult<GoogleMfaAuthAccount> countAll() {
         PagedResult<GoogleMfaAuthAccount> result = new PagedResult<>();
         result.setSize(Long.valueOf(logic.countAll()).intValue());
@@ -89,12 +95,16 @@ public class GoogleMfaAuthAccountServiceImpl extends AbstractServiceImpl impleme
     }
 
     @Override
-    public PagedResult<GoogleMfaAuthAccount> list() {
+    public PagedResult<GoogleMfaAuthAccount> countFor(final String owner) {
         PagedResult<GoogleMfaAuthAccount> result = new PagedResult<>();
-        result.setSize(Long.valueOf(logic.countAll()).intValue());
+        result.setSize(Long.valueOf(logic.countFor(owner)).intValue());
         result.setPage(1);
         result.setTotalCount(result.getSize());
-        result.getResult().addAll(logic.list());
         return result;
     }
+
+    @Override
+    public List<GoogleMfaAuthAccount> list() {
+        return logic.list();
+    }
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthProfileDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthProfileDAO.java
index 5e4070b..824903b 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthProfileDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthProfileDAO.java
@@ -40,4 +40,6 @@ public interface AuthProfileDAO extends DAO<AuthProfile> {
     void deleteByOwner(String owner);
 
     void delete(AuthProfile authProfile);
+
+    void deleteAll();
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthProfile.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthProfile.java
index 73105cb..4834388 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthProfile.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthProfile.java
@@ -35,9 +35,11 @@ public interface AuthProfile extends Entity {
 
     void setGoogleMfaAuthTokens(List<GoogleMfaAuthToken> tokens);
 
-    GoogleMfaAuthAccount getGoogleMfaAuthAccount();
+    List<GoogleMfaAuthAccount> getGoogleMfaAuthAccounts();
 
-    void setGoogleMfaAuthAccount(GoogleMfaAuthAccount account);
+    void setGoogleMfaAuthAccounts(List<GoogleMfaAuthAccount> accounts);
 
     void add(GoogleMfaAuthToken token);
+
+    void add(GoogleMfaAuthAccount account);
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthProfileDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthProfileDAO.java
index d688a85..a8089a1 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthProfileDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthProfileDAO.java
@@ -88,4 +88,11 @@ public class JPAAuthProfileDAO extends AbstractDAO<AuthProfile> implements AuthP
     public void delete(final AuthProfile authProfile) {
         entityManager().remove(authProfile);
     }
+
+    @Override
+    public void deleteAll() {
+        entityManager().
+            createQuery("DELETE FROM " + JPAAuthProfile.class.getSimpleName()).
+            executeUpdate();
+    }
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java
index d2b6e42..f5e8089 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java
@@ -43,7 +43,7 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     private static final long serialVersionUID = 57352617217394093L;
 
     @Lob
-    private String googleMfaAuthAccount;
+    private String googleMfaAuthAccounts;
 
     @Lob
     private String googleMfaAuthTokens;
@@ -75,16 +75,16 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     }
 
     @Override
-    public GoogleMfaAuthAccount getGoogleMfaAuthAccount() {
-        return googleMfaAuthAccount == null
-            ? null
-            : POJOHelper.deserialize(googleMfaAuthAccount, new TypeReference<GoogleMfaAuthAccount>() {
+    public List<GoogleMfaAuthAccount> getGoogleMfaAuthAccounts() {
+        return googleMfaAuthAccounts == null
+            ? new ArrayList<>(0)
+            : POJOHelper.deserialize(googleMfaAuthAccounts, new TypeReference<List<GoogleMfaAuthAccount>>() {
         });
     }
 
     @Override
-    public void setGoogleMfaAuthAccount(final GoogleMfaAuthAccount account) {
-        this.googleMfaAuthAccount = POJOHelper.serialize(account);
+    public void setGoogleMfaAuthAccounts(final List<GoogleMfaAuthAccount> accounts) {
+        this.googleMfaAuthAccounts = POJOHelper.serialize(accounts);
     }
 
     @Override
@@ -94,4 +94,12 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
         tokens.add(token);
         setGoogleMfaAuthTokens(tokens);
     }
+
+    @Override
+    public void add(final GoogleMfaAuthAccount account) {
+        checkType(account, GoogleMfaAuthAccount.class);
+        final List<GoogleMfaAuthAccount> accounts = getGoogleMfaAuthAccounts();
+        accounts.add(account);
+        setGoogleMfaAuthAccounts(accounts);
+    }
 }
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthProfileTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthProfileTest.java
index 6341e3c..070cc1e 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthProfileTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthProfileTest.java
@@ -24,6 +24,8 @@ import org.apache.syncope.core.persistence.api.dao.auth.AuthProfileDAO;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.auth.AuthProfile;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.spring.security.SecureRandomUtils;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -31,7 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.util.Date;
 import java.util.List;
 import java.util.Optional;
-import java.util.UUID;
+
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -46,9 +48,14 @@ public class AuthProfileTest extends AbstractTest {
     @Autowired
     private EntityFactory entityFactory;
 
+    @BeforeEach
+    public void beforeEach() {
+        authProfileDAO.deleteAll();
+    }
+
     @Test
     public void googleMfaToken() {
-        String id = UUID.randomUUID().toString();
+        String id = SecureRandomUtils.generateRandomUUID().toString();
 
         createAuthProfileWithToken(id, 123456);
 
@@ -70,7 +77,7 @@ public class AuthProfileTest extends AbstractTest {
 
     @Test
     public void googleMfaAccount() {
-        String id = UUID.randomUUID().toString();
+        String id = SecureRandomUtils.generateRandomUUID().toString();
 
         createAuthProfileWithAccount(id);
 
@@ -83,13 +90,14 @@ public class AuthProfileTest extends AbstractTest {
         result = authProfileDAO.findByKey(authProfile.getKey());
         assertTrue(result.isPresent());
 
-        String secret = UUID.randomUUID().toString();
-        GoogleMfaAuthAccount googleMfaAuthAccount = authProfile.getGoogleMfaAuthAccount();
+        String secret = SecureRandomUtils.generateRandomUUID().toString();
+        List<GoogleMfaAuthAccount> googleMfaAuthAccounts = authProfile.getGoogleMfaAuthAccounts();
+        GoogleMfaAuthAccount googleMfaAuthAccount = googleMfaAuthAccounts.get(0);
         googleMfaAuthAccount.setSecretKey(secret);
-        authProfile.setGoogleMfaAuthAccount(googleMfaAuthAccount);
-        authProfileDAO.save(authProfile);
-
-        assertEquals(secret, authProfileDAO.findByOwner(id).get().getGoogleMfaAuthAccount().getSecretKey());
+        
+        authProfile.setGoogleMfaAuthAccounts(googleMfaAuthAccounts);
+        authProfile = authProfileDAO.save(authProfile);
+        assertEquals(secret, authProfile.getGoogleMfaAuthAccounts().get(0).getSecretKey());
     }
 
     private AuthProfile createAuthProfileWithToken(final String owner, final Integer otp) {
@@ -107,14 +115,15 @@ public class AuthProfileTest extends AbstractTest {
     private AuthProfile createAuthProfileWithAccount(final String owner) {
         AuthProfile profile = entityFactory.newEntity(AuthProfile.class);
         profile.setOwner(owner);
-        GoogleMfaAuthAccount token = new GoogleMfaAuthAccount.Builder()
+        GoogleMfaAuthAccount account = new GoogleMfaAuthAccount.Builder()
             .registrationDate(new Date())
             .scratchCodes(List.of(1, 2, 3, 4, 5))
-            .secretKey(UUID.randomUUID().toString())
+            .secretKey(SecureRandomUtils.generateRandomUUID().toString())
             .validationCode(123456)
             .owner(owner)
+            .name(SecureRandomUtils.generateRandomUUID().toString())
             .build();
-        profile.setGoogleMfaAuthAccount(token);
+        profile.add(account);
         return authProfileDAO.save(profile);
     }
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GoogleMfaAuthAccountITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GoogleMfaAuthAccountITCase.java
index b899307..1b8143e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GoogleMfaAuthAccountITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GoogleMfaAuthAccountITCase.java
@@ -21,6 +21,7 @@ package org.apache.syncope.fit.core;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.types.GoogleMfaAuthAccount;
 import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.core.spring.security.SecureRandomUtils;
 import org.apache.syncope.fit.AbstractITCase;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -29,23 +30,24 @@ import javax.ws.rs.core.Response;
 
 import java.util.Date;
 import java.util.List;
-import java.util.UUID;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 public class GoogleMfaAuthAccountITCase extends AbstractITCase {
 
     private static GoogleMfaAuthAccount createGoogleMfaAuthAccount() {
-        String id = UUID.randomUUID().toString();
+        String id = SecureRandomUtils.generateRandomUUID().toString();
         return new GoogleMfaAuthAccount.Builder()
             .registrationDate(new Date())
             .scratchCodes(List.of(1, 2, 3, 4, 5))
-            .secretKey(UUID.randomUUID().toString())
+            .secretKey(SecureRandomUtils.generateRandomUUID().toString())
             .validationCode(123456)
             .owner(id)
+            .name(SecureRandomUtils.generateRandomUUID().toString())
             .build();
     }
 
@@ -72,8 +74,10 @@ public class GoogleMfaAuthAccountITCase extends AbstractITCase {
     public void count() {
         GoogleMfaAuthAccount acct = createGoogleMfaAuthAccount();
         googleMfaAuthAccountService.save(acct);
+        assertFalse(googleMfaAuthAccountService.list().isEmpty());
         assertEquals(1, googleMfaAuthAccountService.countAll().getTotalCount());
-        assertNotNull(googleMfaAuthAccountService.findAccountFor(acct.getOwner()));
+        assertEquals(1, googleMfaAuthAccountService.countFor(acct.getOwner()).getTotalCount());
+        assertFalse(googleMfaAuthAccountService.findAccountsFor(acct.getOwner()).isEmpty());
     }
 
     @Test
@@ -82,9 +86,9 @@ public class GoogleMfaAuthAccountITCase extends AbstractITCase {
         Response response = googleMfaAuthAccountService.save(acct);
         String key = response.getHeaderString(RESTHeaders.RESOURCE_KEY);
         assertNotNull(key);
-        response = googleMfaAuthAccountService.deleteAccountFor(acct.getOwner());
+        response = googleMfaAuthAccountService.deleteAccountsFor(acct.getOwner());
         assertEquals(response.getStatusInfo().getStatusCode(), Response.Status.NO_CONTENT.getStatusCode());
-        assertThrows(SyncopeClientException.class, () -> googleMfaAuthAccountService.findAccountFor(acct.getOwner()));
+        assertThrows(SyncopeClientException.class, () -> googleMfaAuthAccountService.findAccountsFor(acct.getOwner()));
     }
 
     @Test
@@ -93,11 +97,12 @@ public class GoogleMfaAuthAccountITCase extends AbstractITCase {
         Response response = googleMfaAuthAccountService.save(acct);
         String key = response.getHeaderString(RESTHeaders.RESOURCE_KEY);
         acct = googleMfaAuthAccountService.findAccountBy(key);
+        acct = googleMfaAuthAccountService.findAccountBy(acct.getId());
         acct.setSecretKey("NewSecret");
         acct.setScratchCodes(List.of(9, 8, 7, 6, 5));
         googleMfaAuthAccountService.update(acct);
         assertEquals(1, googleMfaAuthAccountService.countAll().getTotalCount());
-        acct = googleMfaAuthAccountService.findAccountFor(acct.getOwner());
+        acct = googleMfaAuthAccountService.findAccountsFor(acct.getOwner()).get(0);
         assertEquals(acct.getSecretKey(), acct.getSecretKey());
         googleMfaAuthAccountService.deleteAccountBy(acct.getKey());
     }
diff --git a/pom.xml b/pom.xml
index 2ee8344..917a197 100644
--- a/pom.xml
+++ b/pom.xml
@@ -446,7 +446,7 @@ under the License.
     <commons-text.version>1.8</commons-text.version>
     <commons-logging.version>1.1.3</commons-logging.version>
     
-    <cas.version>6.2.0</cas.version>
+    <cas.version>6.3.0-SNAPSHOT</cas.version>
 
     <h2.version>1.4.200</h2.version>
 
diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
index 125db91..d051d2e 100644
--- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
+++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
@@ -263,7 +263,7 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         props.setAttributeConsumingServiceIndex(conf.getAttributeConsumingServiceIndex());
         props.setAuthnContextClassRef(conf.getAuthnContextClassRefs());
         props.setAuthnContextComparisonType(conf.getAuthnContextComparisonType());
-        props.setBlackListedSignatureSigningAlgorithms(conf.getBlackListedSignatureSigningAlgorithms());
+        props.setBlockedSignatureSigningAlgorithms(conf.getBlackListedSignatureSigningAlgorithms());
         props.setDestinationBinding(conf.getDestinationBinding());
         props.setIdentityProviderMetadataPath(conf.getIdentityProviderMetadataPath());
         props.setKeystoreAlias(conf.getKeystoreAlias());
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
index 0cce830..423cdea 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
@@ -63,7 +63,6 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.io.ResourceLoader;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -76,9 +75,6 @@ public class SyncopeWAConfiguration {
     private CasConfigurationProperties casProperties;
 
     @Autowired
-    private ResourceLoader resourceLoader;
-
-    @Autowired
     @Qualifier("samlSelfSignedCertificateWriter")
     private ObjectProvider<SamlIdPCertificateAndKeyWriter> samlSelfSignedCertificateWriter;
 
@@ -151,7 +147,7 @@ public class SyncopeWAConfiguration {
             SamlIdPMetadataGeneratorConfigurationContext.builder().
                 samlIdPMetadataLocator(samlIdPMetadataLocator(restClient)).
                 samlIdPCertificateAndKeyWriter(samlSelfSignedCertificateWriter.getObject()).
-                resourceLoader(resourceLoader).
+                applicationContext(applicationContext).
                 casProperties(casProperties).
                 metadataCipherExecutor(CipherExecutor.noOpOfStringToString()).
                 build();
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/gauth/credential/SyncopeWAGoogleMfaAuthCredentialRepository.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/gauth/credential/SyncopeWAGoogleMfaAuthCredentialRepository.java
index 584ee7f..569cb7c 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/gauth/credential/SyncopeWAGoogleMfaAuthCredentialRepository.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/gauth/credential/SyncopeWAGoogleMfaAuthCredentialRepository.java
@@ -28,12 +28,15 @@ import com.warrenstrange.googleauth.IGoogleAuthenticator;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.GoogleMfaAuthAccount;
+import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.service.wa.GoogleMfaAuthAccountService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.apache.syncope.wa.starter.gauth.token.SyncopeWAGoogleMfaAuthTokenRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.ws.rs.core.Response;
+
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -45,22 +48,65 @@ public class SyncopeWAGoogleMfaAuthCredentialRepository extends BaseGoogleAuthen
     private final WARestClient waRestClient;
 
     public SyncopeWAGoogleMfaAuthCredentialRepository(final WARestClient waRestClient,
-                                                         final IGoogleAuthenticator googleAuthenticator) {
+                                                      final IGoogleAuthenticator googleAuthenticator) {
         super(CipherExecutor.noOpOfStringToString(), googleAuthenticator);
         this.waRestClient = waRestClient;
     }
 
+    private static GoogleMfaAuthAccount mapGoogleMfaAuthAccount(final OneTimeTokenAccount account) {
+        return new GoogleMfaAuthAccount.Builder()
+            .owner(account.getUsername())
+            .registrationDate(new Date())
+            .scratchCodes(account.getScratchCodes())
+            .validationCode(account.getValidationCode())
+            .secretKey(account.getSecretKey())
+            .id(account.getId())
+            .build();
+    }
+
+    private static GoogleAuthenticatorAccount mapGoogleMfaAuthAccount(final GoogleMfaAuthAccount account) {
+        return GoogleAuthenticatorAccount.builder().
+            username(account.getOwner()).
+            secretKey(account.getSecretKey()).
+            validationCode(account.getValidationCode()).
+            scratchCodes(account.getScratchCodes()).
+            name(account.getName()).
+            id(account.getId()).
+            build();
+    }
+
     @Override
-    public OneTimeTokenAccount get(final String username) {
+    public OneTimeTokenAccount get(final long id) {
         try {
             GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
                 getService(GoogleMfaAuthAccountService.class);
-            GoogleMfaAuthAccount account = googleService.findAccountFor(username);
-            return new GoogleAuthenticatorAccount(account.getOwner(),
-                account.getSecretKey(), account.getValidationCode(), account.getScratchCodes());
+            GoogleMfaAuthAccount account = googleService.findAccountBy(id);
+            if (account != null) {
+                return mapGoogleMfaAuthAccount(account);
+            }
         } catch (final SyncopeClientException e) {
             if (e.getType() == ClientExceptionType.NotFound) {
-                LOG.info("Could not locate account for owner {}", username);
+                LOG.info("Could not locate account for id {}", id);
+            } else {
+                LOG.error(e.getMessage(), e);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public OneTimeTokenAccount get(final String username, final long id) {
+        try {
+            GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
+                getService(GoogleMfaAuthAccountService.class);
+            googleService.findAccountsFor(username).
+                stream().
+                filter(account -> account.getId() == id).
+                map(SyncopeWAGoogleMfaAuthCredentialRepository::mapGoogleMfaAuthAccount).
+                collect(Collectors.toList());
+        } catch (final SyncopeClientException e) {
+            if (e.getType() == ClientExceptionType.NotFound) {
+                LOG.info("Could not locate account for owner {} and id {}", username, id);
             } else {
                 LOG.error(e.getMessage(), e);
             }
@@ -69,43 +115,58 @@ public class SyncopeWAGoogleMfaAuthCredentialRepository extends BaseGoogleAuthen
     }
 
     @Override
+    public Collection<? extends OneTimeTokenAccount> get(final String username) {
+        try {
+            GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
+                getService(GoogleMfaAuthAccountService.class);
+            googleService.findAccountsFor(username).
+                stream().
+                map(SyncopeWAGoogleMfaAuthCredentialRepository::mapGoogleMfaAuthAccount).
+                collect(Collectors.toList());
+        } catch (final SyncopeClientException e) {
+            if (e.getType() == ClientExceptionType.NotFound) {
+                LOG.info("Could not locate account for owner {}", username);
+            } else {
+                LOG.error(e.getMessage(), e);
+            }
+        }
+        return List.of();
+    }
+
+    @Override
     public Collection<? extends OneTimeTokenAccount> load() {
         GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
             getService(GoogleMfaAuthAccountService.class);
         return googleService.list().
-            getResult().
             stream().
-            map(account -> new GoogleAuthenticatorAccount(account.getOwner(),
-                account.getSecretKey(), account.getValidationCode(), account.getScratchCodes())).
+            map(SyncopeWAGoogleMfaAuthCredentialRepository::mapGoogleMfaAuthAccount).
             collect(Collectors.toList());
     }
 
     @Override
-    public void save(final String userName, final String secretKey,
-                     final int validationCode, final List<Integer> scratchCodes) {
+    public OneTimeTokenAccount save(final OneTimeTokenAccount tokenAccount) {
         GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
             getService(GoogleMfaAuthAccountService.class);
         GoogleMfaAuthAccount account = new GoogleMfaAuthAccount.Builder()
-            .owner(userName)
+            .owner(tokenAccount.getUsername())
             .registrationDate(new Date())
-            .scratchCodes(scratchCodes)
-            .validationCode(validationCode)
-            .secretKey(secretKey)
+            .scratchCodes(tokenAccount.getScratchCodes())
+            .validationCode(tokenAccount.getValidationCode())
+            .secretKey(tokenAccount.getSecretKey())
+            .name(tokenAccount.getName())
+            .id(tokenAccount.getId())
             .build();
-        googleService.save(account);
+        Response response = googleService.save(account);
+        String key = response.getHeaderString(RESTHeaders.RESOURCE_KEY);
+        account.setKey(key);
+        return mapGoogleMfaAuthAccount(account);
     }
 
     @Override
     public OneTimeTokenAccount update(final OneTimeTokenAccount account) {
         GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
             getService(GoogleMfaAuthAccountService.class);
-        GoogleMfaAuthAccount acct = new GoogleMfaAuthAccount.Builder()
-            .owner(account.getUsername())
-            .registrationDate(new Date())
-            .scratchCodes(account.getScratchCodes())
-            .validationCode(account.getValidationCode())
-            .secretKey(account.getSecretKey())
-            .build();
+        GoogleMfaAuthAccount acct = mapGoogleMfaAuthAccount(account);
         googleService.update(acct);
         return account;
     }
@@ -121,7 +182,7 @@ public class SyncopeWAGoogleMfaAuthCredentialRepository extends BaseGoogleAuthen
     public void delete(final String username) {
         GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
             getService(GoogleMfaAuthAccountService.class);
-        googleService.deleteAccountFor(username);
+        googleService.deleteAccountsFor(username);
     }
 
     @Override
@@ -130,4 +191,11 @@ public class SyncopeWAGoogleMfaAuthCredentialRepository extends BaseGoogleAuthen
             getService(GoogleMfaAuthAccountService.class);
         return googleService.countAll().getTotalCount();
     }
+
+    @Override
+    public long count(final String username) {
+        GoogleMfaAuthAccountService googleService = waRestClient.getSyncopeClient().
+            getService(GoogleMfaAuthAccountService.class);
+        return googleService.countFor(username).getTotalCount();
+    }
 }
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java
index 990c7fd..640fa2c 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java
@@ -25,6 +25,7 @@ import org.springframework.test.context.ContextConfiguration;
 
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
     "cas.authn.accept.users=mrossi::password",
+    "cas.authn.syncope.url=http://localhost:8080",
     "cas.sso.allow-missing-service-parameter=true"
 })
 @ContextConfiguration(initializers = ZookeeperTestingServer.class)
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java
index 1884cd0..d336ac2 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java
@@ -90,7 +90,7 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
         return saml2spto;
     }
 
-    private void addAttributes(final boolean withReleaseAttributes,
+    private static void addAttributes(final boolean withReleaseAttributes,
             final boolean withAttrReleasePolicy,
             final WAClientApp waClientApp) {
         DefaultAuthPolicyConf authPolicyConf = new DefaultAuthPolicyConf();
@@ -137,12 +137,12 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
         waClientApp.setClientAppTO(buildOIDCRP());
         Long clientAppId = waClientApp.getClientAppTO().getClientAppId();
         addAttributes(true, true, waClientApp);
-
+        
         SyncopeCoreTestingServer.APPS.add(waClientApp);
         List<WAClientApp> apps = service.list();
         assertEquals(1, apps.size());
 
-        assertNull(servicesManager.findServiceBy(clientAppId));
+        assertNotNull(servicesManager.findServiceBy(clientAppId));
 
         // 3. trigger client app refresh
         Collection<RegisteredService> load = servicesManager.load();