keycloak-aplcache

Details

diff --git a/forms/account-api/src/main/java/org/keycloak/account/Account.java b/forms/account-api/src/main/java/org/keycloak/account/Account.java
index f92b161..5a62fec 100644
--- a/forms/account-api/src/main/java/org/keycloak/account/Account.java
+++ b/forms/account-api/src/main/java/org/keycloak/account/Account.java
@@ -31,5 +31,5 @@ public interface Account {
 
     Account setEvents(List<Event> events);
 
-    Account setFeatures(boolean social, boolean audit);
+    Account setFeatures(boolean social, boolean audit, boolean passwordUpdateSupported);
 }
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccount.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccount.java
index 53f43d4..9b6f0d8 100644
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccount.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccount.java
@@ -44,6 +44,7 @@ public class FreeMarkerAccount implements Account {
     private List<Event> events;
     private boolean social;
     private boolean audit;
+    private boolean passwordUpdateSupported;
 
     public static enum MessageType {SUCCESS, WARNING, ERROR}
 
@@ -95,7 +96,7 @@ public class FreeMarkerAccount implements Account {
 
         attributes.put("url", new UrlBean(realm, theme, baseUri));
 
-        attributes.put("features", new FeaturesBean(social, audit));
+        attributes.put("features", new FeaturesBean(social, audit, passwordUpdateSupported));
 
         switch (page) {
             case ACCOUNT:
@@ -172,9 +173,10 @@ public class FreeMarkerAccount implements Account {
     }
 
     @Override
-    public Account setFeatures(boolean social, boolean audit) {
+    public Account setFeatures(boolean social, boolean audit, boolean passwordUpdateSupported) {
         this.social = social;
         this.audit = audit;
+        this.passwordUpdateSupported = passwordUpdateSupported;
         return this;
     }
 }
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/FeaturesBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/FeaturesBean.java
index 6f8158b..06e99eb 100644
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/FeaturesBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/FeaturesBean.java
@@ -7,10 +7,12 @@ public class FeaturesBean {
 
     private final boolean social;
     private final boolean log;
+    private final boolean passwordUpdateSupported;
 
-    public FeaturesBean(boolean social, boolean log) {
+    public FeaturesBean(boolean social, boolean log, boolean passwordUpdateSupported) {
         this.social = social;
         this.log = log;
+        this.passwordUpdateSupported = passwordUpdateSupported;
     }
 
     public boolean isSocial() {
@@ -21,4 +23,7 @@ public class FeaturesBean {
         return log;
     }
 
+    public boolean isPasswordUpdateSupported() {
+        return passwordUpdateSupported;
+    }
 }
diff --git a/forms/common-themes/src/main/resources/theme/account/base/template.ftl b/forms/common-themes/src/main/resources/theme/account/base/template.ftl
index 6a39817..883d8fb 100644
--- a/forms/common-themes/src/main/resources/theme/account/base/template.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/template.ftl
@@ -40,7 +40,7 @@
         <div class="bs-sidebar col-sm-3  ng-scope">
             <ul>
                 <li class="<#if active=='account'>active</#if>"><a href="${url.accountUrl}">Account</a></li>
-                <li class="<#if active=='password'>active</#if>"><a href="${url.passwordUrl}">Password</a></li>
+                <#if features.passwordUpdateSupported><li class="<#if active=='password'>active</#if>"><a href="${url.passwordUrl}">Password</a></li></#if>
                 <li class="<#if active=='totp'>active</#if>"><a href="${url.totpUrl}">Authenticator</a></li>
                 <#if features.social><li class="<#if active=='social'>active</#if>"><a href="${url.socialUrl}">Social</a></li></#if>
                 <#if features.log><li class="<#if active=='log'>active</#if>"><a href="${url.logUrl}">Log</a></li></#if>
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 a789660..bdc97fe 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -35,6 +35,8 @@ import org.keycloak.audit.Events;
 import org.keycloak.jaxrs.JaxrsOAuthClient;
 import org.keycloak.models.AccountRoles;
 import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.AuthenticationProviderModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.RealmModel;
@@ -143,12 +145,21 @@ public class AccountService {
     public void init() {
         auditProvider = providers.getProvider(AuditProvider.class);
 
-        account = AccountLoader.load().createAccount(uriInfo).setRealm(realm).setFeatures(realm.isSocial(), auditProvider != null);
+        account = AccountLoader.load().createAccount(uriInfo).setRealm(realm);
 
+        boolean passwordUpdateSupported = false;
         auth = authManager.authenticate(realm, headers);
         if (auth != null) {
             account.setUser(auth.getUser());
+
+            AuthenticationLinkModel authLinkModel = realm.getAuthenticationLink(auth.getUser());
+            if (authLinkModel != null) {
+                AuthenticationProviderModel authProviderModel = AuthenticationProviderManager.getConfiguredProviderModel(realm, authLinkModel.getAuthProvider());
+                passwordUpdateSupported = authProviderModel.isPasswordUpdateSupported();
+            }
         }
+
+        account.setFeatures(realm.isSocial(), auditProvider != null, passwordUpdateSupported);
     }
 
     public static UriBuilder accountServiceBaseUrl(UriInfo uriInfo) {
diff --git a/spi/authentication-spi/src/main/java/org/keycloak/spi/authentication/AuthenticationProviderManager.java b/spi/authentication-spi/src/main/java/org/keycloak/spi/authentication/AuthenticationProviderManager.java
index 4c540a8..823a14b 100644
--- a/spi/authentication-spi/src/main/java/org/keycloak/spi/authentication/AuthenticationProviderManager.java
+++ b/spi/authentication-spi/src/main/java/org/keycloak/spi/authentication/AuthenticationProviderManager.java
@@ -182,7 +182,7 @@ public class AuthenticationProviderManager {
         return delegate;
     }
 
-    private List<AuthenticationProviderModel> getConfiguredProviderModels(RealmModel realm) {
+    private static List<AuthenticationProviderModel> getConfiguredProviderModels(RealmModel realm) {
         List<AuthenticationProviderModel> configuredProviders = realm.getAuthenticationProviders();
 
         // Use model based authentication of current realm by default
@@ -194,7 +194,7 @@ public class AuthenticationProviderManager {
         return configuredProviders;
     }
 
-    private AuthenticationProviderModel getConfiguredProviderModel(RealmModel realm, String providerName) {
+    public static AuthenticationProviderModel getConfiguredProviderModel(RealmModel realm, String providerName) {
         List<AuthenticationProviderModel> providers = getConfiguredProviderModels(realm);
         for (AuthenticationProviderModel provider : providers) {
             if (providerName.equals(provider.getProviderName())) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
index 6a22cd7..7bf2e3a 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
@@ -115,6 +115,9 @@ public class AuthProvidersIntegrationTest {
 
         Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
         Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
+
+        profilePage.open();
+        Assert.assertFalse(profilePage.isPasswordUpdateSupported());
     }
 
     @Test
@@ -124,6 +127,9 @@ public class AuthProvidersIntegrationTest {
 
         Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
         Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
+
+        profilePage.open();
+        Assert.assertTrue(profilePage.isPasswordUpdateSupported());
     }
 
     @Test
@@ -135,6 +141,7 @@ public class AuthProvidersIntegrationTest {
         Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
 
         profilePage.open();
+        Assert.assertTrue(profilePage.isPasswordUpdateSupported());
         Assert.assertEquals("John", profilePage.getFirstName());
         Assert.assertEquals("Doe", profilePage.getLastName());
         Assert.assertEquals("john@email.org", profilePage.getEmail());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
index 582c112..04f1c60 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
@@ -96,4 +96,8 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
     public String getError() {
         return errorMessage.getText();
     }
+
+    public boolean isPasswordUpdateSupported() {
+        return driver.getPageSource().contains(PATH + "/password");
+    }
 }