keycloak-memoizeit

KEYCLOAK-361 it shouldn't be possible to remove last social

5/7/2014 10:02:57 AM

Details

diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java
index 2fbe8c6..481f1d9 100644
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java
@@ -21,6 +21,7 @@ import org.keycloak.social.SocialProvider;
 public class AccountSocialBean {
 
     private final List<SocialLinkEntry> socialLinks;
+    private final boolean removeLinkPossible;
 
     public AccountSocialBean(RealmModel realm, UserModel user, URI baseUri) {
         URI accountSocialUpdateUri = Urls.accountSocialUpdate(baseUri, realm.getName());
@@ -29,12 +30,16 @@ public class AccountSocialBean {
         Map<String, String> socialConfig = realm.getSocialConfig();
         Set<SocialLinkModel> userSocialLinks = realm.getSocialLinks(user);
 
+        int availableLinks = 0;
         if (socialConfig != null && !socialConfig.isEmpty()) {
             for (SocialProvider provider : SocialLoader.load()) {
                 String socialProviderId = provider.getId();
                 if (socialConfig.containsKey(socialProviderId + ".key")) {
                     SocialLinkModel socialLink = getSocialLink(userSocialLinks, socialProviderId);
 
+                    if (socialLink != null) {
+                        availableLinks++;
+                    }
                     String action = socialLink != null ? "remove" : "add";
                     String actionUrl = UriBuilder.fromUri(accountSocialUpdateUri).queryParam("action", action).queryParam("provider_id", socialProviderId).build().toString();
 
@@ -43,6 +48,9 @@ public class AccountSocialBean {
                 }
             }
         }
+
+        // Removing last social provider is not possible if you don't have other possibility to authenticate
+        this.removeLinkPossible = availableLinks > 1 || realm.getAuthenticationLink(user) != null;
     }
 
     private SocialLinkModel getSocialLink(Set<SocialLinkModel> userSocialLinks, String socialProviderId) {
@@ -58,6 +66,10 @@ public class AccountSocialBean {
         return socialLinks;
     }
 
+    public boolean isRemoveLinkPossible() {
+        return removeLinkPossible;
+    }
+
     public class SocialLinkEntry {
 
         private SocialLinkModel link;
diff --git a/forms/common-themes/src/main/resources/theme/account/base/messages/messages.properties b/forms/common-themes/src/main/resources/theme/account/base/messages/messages.properties
index 1945c64..152f61c 100755
--- a/forms/common-themes/src/main/resources/theme/account/base/messages/messages.properties
+++ b/forms/common-themes/src/main/resources/theme/account/base/messages/messages.properties
@@ -30,6 +30,7 @@ missingSocialProvider=Social provider not specified
 invalidSocialAction=Invalid or missing action
 socialProviderNotFound=Specified social provider not found
 socialLinkNotActive=This social link is not active anymore
+socialRemovingLastProvider=You can't remove last social provider as you don't have password
 socialRedirectError=Failed to redirect to social provider
 socialProviderRemoved=Social provider removed successfully
 
diff --git a/forms/common-themes/src/main/resources/theme/account/base/social.ftl b/forms/common-themes/src/main/resources/theme/account/base/social.ftl
index e238248..2bba805 100644
--- a/forms/common-themes/src/main/resources/theme/account/base/social.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/social.ftl
@@ -18,7 +18,9 @@
                 </div>
                 <div class="col-sm-5 col-md-5">
                     <#if socialLink.connected>
-                        <a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Remove ${socialLink.providerName!}</a>
+                        <#if social.removeLinkPossible>
+                            <a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Remove ${socialLink.providerName!}</a>
+                        </#if>
                     <#else>
                         <a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Add ${socialLink.providerName!}</a>
                     </#if>
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index cc0ab1d..01c6f80 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -71,6 +71,8 @@ public class Messages {
 
     public static final String SOCIAL_LINK_NOT_ACTIVE = "socialLinkNotActive";
 
+    public static final String SOCIAL_REMOVING_LAST_PROVIDER = "socialRemovingLastProvider";
+
     public static final String SOCIAL_REDIRECT_ERROR = "socialRedirectError";
 
     public static final String SOCIAL_PROVIDER_REMOVED = "socialProviderRemoved";
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 1a45b6c..3666600 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -422,15 +422,21 @@ public class AccountService {
             case REMOVE:
                 SocialLinkModel link = realm.getSocialLink(user, providerId);
                 if (link != null) {
-                    realm.removeSocialLink(user, providerId);
 
-                    logger.debug("Social provider " + providerId + " removed successfully from user " + user.getLoginName());
+                    // Removing last social provider is not possible if you don't have other possibility to authenticate
+                    if (realm.getSocialLinks(user).size() > 1 || realm.getAuthenticationLink(user) != null) {
+                        realm.removeSocialLink(user, providerId);
 
-                    audit.event(Events.REMOVE_SOCIAL_LINK).client(auth.getClient()).user(auth.getUser())
-                            .detail(Details.USERNAME, link.getSocialUserId() + "@" + link.getSocialProvider())
-                            .success();
+                        logger.debug("Social provider " + providerId + " removed successfully from user " + user.getLoginName());
 
-                    return account.setSuccess(Messages.SOCIAL_PROVIDER_REMOVED).createResponse(AccountPages.SOCIAL);
+                        audit.event(Events.REMOVE_SOCIAL_LINK).client(auth.getClient()).user(auth.getUser())
+                                .detail(Details.USERNAME, link.getSocialUserId() + "@" + link.getSocialProvider())
+                                .success();
+
+                        return account.setSuccess(Messages.SOCIAL_PROVIDER_REMOVED).createResponse(AccountPages.SOCIAL);
+                    } else {
+                        return account.setError(Messages.SOCIAL_REMOVING_LAST_PROVIDER).createResponse(AccountPages.SOCIAL);
+                    }
                 } else {
                     return account.setError(Messages.SOCIAL_LINK_NOT_ACTIVE).createResponse(AccountPages.SOCIAL);
                 }
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index b0be76b..74c30bb 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -174,6 +174,10 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.twitter4j</groupId>
+            <artifactId>twitter4j-core</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-social-facebook</artifactId>
             <version>${project.version}</version>