keycloak-uncached

props

8/2/2016 7:50:13 AM

Details

diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 8270ed4..b58fbe5 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -207,6 +207,18 @@ public class RealmAdminResource {
     }
 
     /**
+     * Base path for managing components under this realm.
+     *
+     * @return
+     */
+    @Path("components")
+    public ComponentResource getComponents() {
+        ComponentResource resource = new ComponentResource(realm, auth, adminEvent);
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+        return resource;
+    }
+
+    /**
      * base path for managing realm-level roles of this realm
      *
      * @return
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
index 644dcb8..489dccd 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
@@ -52,7 +52,7 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
         this.session = session;
         this.model = model;
         this.userPasswords = userPasswords;
-        this.federatedStorageEnabled = model.getConfig().containsKey("USER_FEDERATED_STORAGE");
+        this.federatedStorageEnabled = model.getConfig().containsKey("federatedStorage") && Boolean.valueOf(model.getConfig().getFirst("federatedStorage")).booleanValue();
     }
 
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
index 0dec2bb..291f084 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
@@ -20,9 +20,12 @@ import org.keycloak.Config;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.storage.UserStorageProviderFactory;
 
 import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -38,7 +41,7 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
     public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
         Properties props = new Properties();
         try {
-            props.load(getClass().getResourceAsStream(model.getConfig().getFirst("property.file")));
+            props.load(getClass().getResourceAsStream(model.getConfig().getFirst("propertyFile")));
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
@@ -50,6 +53,19 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
         return PROVIDER_ID;
     }
 
+    static List<ProviderConfigProperty> OPTIONS = new LinkedList<>();
+    static {
+        ProviderConfigProperty prop = new ProviderConfigProperty("propertyFile", "Property File", "file that contains name value pairs", ProviderConfigProperty.STRING_TYPE, null);
+        OPTIONS.add(prop);
+        prop = new ProviderConfigProperty("federatedStorage", "User Federated Storage", "use federated storage?", ProviderConfigProperty.BOOLEAN_TYPE, null);
+        OPTIONS.add(prop);
+
+    }
+    @Override
+    public List<ProviderConfigProperty> getConfigProperties() {
+         return OPTIONS;
+    }
+
     @Override
     public void init(Config.Scope config) {
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
index aa648b6..3e75d64 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
@@ -67,15 +67,15 @@ public class UserStorageTest {
             model.setPriority(1);
             model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
             model.setParentId(appRealm.getId());
-            model.getConfig().putSingle("property.file", "/storage-test/read-only-user-password.properties");
+            model.getConfig().putSingle("propertyFile", "/storage-test/read-only-user-password.properties");
             appRealm.addComponentModel(model);
             model = new UserStorageProviderModel();
             model.setName("user-props");
             model.setPriority(2);
             model.setParentId(appRealm.getId());
             model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
-            model.getConfig().putSingle("property.file", "/storage-test/user-password.properties");
-            model.getConfig().putSingle("USER_FEDERATED_STORAGE", "true");
+            model.getConfig().putSingle("propertyFile", "/storage-test/user-password.properties");
+            model.getConfig().putSingle("federatedStorage", "true");
             appRealm.addComponentModel(model);
         }
     });
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 1f39b06..9efe97e 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -585,6 +585,7 @@ add-client-template=Add client template
 manage=Manage
 authentication=Authentication
 user-federation=User Federation
+user-storage=User Storage
 events=Events
 realm-settings=Realm Settings
 configure=Configure
@@ -687,6 +688,7 @@ create-user-federation-mapper=Create user federation mapper
 add-user-federation-mapper=Add user federation mapper
 provider-name=Provider Name
 no-user-federation-providers-configured=No user federation providers configured
+no-user-storage-providers-configured=No user storage providers configured
 add-identity-provider=Add identity provider
 add-identity-provider-link=Add identity provider link
 identity-provider=Identity Provider
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/app.js b/themes/src/main/resources/theme/base/admin/resources/js/app.js
index 1f6f5a8..2609e81 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -1338,6 +1338,18 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmSessionStatsCtrl'
         })
+        .when('/realms/:realm/user-storage', {
+            templateUrl : resourceUrl + '/partials/user-storage.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                serverInfo : function(ServerInfoLoader) {
+                    return ServerInfoLoader();
+                }
+            },
+            controller : 'UserStorageCtrl'
+        })
         .when('/realms/:realm/user-federation', {
             templateUrl : resourceUrl + '/partials/user-federation.html',
             resolve : {
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index 8fb01cf..8f07ffd 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -592,6 +592,34 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, RequiredA
     };
 });
 
+module.controller('UserStorageCtrl', function($scope, $location, $route, realm, serverInfo, Components, Notifications, Dialog) {
+    console.log('UserStorageCtrl ++++****');
+    $scope.realm = realm;
+    $scope.providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider'];
+
+    $scope.addProvider = function(provider) {
+        console.log('Add provider: ' + provider.id);
+        $location.url("/create/user-storage/" + realm.realm + "/providers/" + provider.id);
+    };
+
+    $scope.instances = Components.query({realm: realm.realm,
+        parent: realm.id,
+        type: 'org.keycloak.storage.UserStorageProvider'
+    });
+
+    $scope.removeUserStorage = function(instance) {
+        Dialog.confirmDelete(instance.name, 'user storage provider', function() {
+            Components.remove({
+                realm : realm.realm,
+                componentId : instance.id
+            }, function() {
+                $route.reload();
+                Notifications.success("The provider has been deleted.");
+            });
+        });
+    };
+});
+
 module.controller('UserFederationCtrl', function($scope, $location, $route, realm, UserFederationProviders, UserFederationInstances, Notifications, Dialog) {
     console.log('UserFederationCtrl ++++****');
     $scope.realm = realm;
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index c49a8d5..7e4df38 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -1629,3 +1629,16 @@ module.factory('DefaultGroups', function($resource) {
         }
     });
 });
+
+module.factory('Components', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/components/:componentId', {
+        realm : '@realm',
+        componentId : '@componentId'
+    }, {
+        update : {
+            method : 'PUT'
+        }
+    });
+});
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
new file mode 100755
index 0000000..fb6b87a
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
@@ -0,0 +1,43 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <h1>
+        <span>{{:: 'user-federation' | translate}}</span>
+    </h1>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+        <tr ng-show="providers.length > 0 && access.manageUsers">
+            <th colspan="5" class="kc-table-actions">
+                <div class="pull-right">
+                    <div>
+                        <select class="form-control" ng-model="selectedProvider"
+                                ng-options="p.id for p in providers"
+                                data-ng-change="addProvider(selectedProvider); selectedProvider = null">
+                            <option value="" disabled selected>{{:: 'add-provider.placeholder' | translate}}</option>
+                        </select>
+                    </div>
+                </div>
+            </th>
+        </tr>
+        <tr data-ng-show="instances && instances.length > 0">
+            <th>{{:: 'id' | translate}}</th>
+            <th>{{:: 'provider-name' | translate}}</th>
+            <th>{{:: 'priority' | translate}}</th>
+            <th colspan="2">{{:: 'actions' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="instance in instances">
+            <td><a href="#/realms/{{realm.realm}}/user-storage/providers/{{instance.providerId}}/{{instance.id}}">{{instance.name}}</a></td>
+            <td>{{instance.providerId|capitalize}}</td>
+            <td>{{instance.config['priority'][0]}}</td>
+            <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/user-storage/providers/{{instance.providerId}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
+            <td class="kc-action-cell" data-ng-click="removeUserStorage(instance)">{{:: 'delete' | translate}}</td>
+         </tr>
+        <tr data-ng-show="!instances || instances.length == 0">
+            <td class="text-muted">{{:: 'no-user-storage-providers-configured' | translate}}</td>
+        </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
index e766bcb..926b43c 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
@@ -34,6 +34,7 @@
             <li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'roles' || path[2] == 'default-roles' || (path[1] == 'role' && path[3] != 'clients')) && 'active'"><a href="#/realms/{{realm.realm}}/roles"><i class="fa fa-tasks"></i> {{:: 'roles' | translate}}</a></li>
             <li data-ng-show="access.viewIdentityProviders" data-ng-class="(path[2] == 'identity-provider-settings' || path[2] == 'identity-provider-mappers') && 'active'"><a href="#/realms/{{realm.realm}}/identity-provider-settings"><i class="fa fa-exchange"></i> {{:: 'identity-providers' | translate}}</a></li>
             <li data-ng-show="access.viewUsers" data-ng-class="(path[1] == 'user-federation' || path[2] == 'user-federation') && 'active'"><a href="#/realms/{{realm.realm}}/user-federation"><i class="fa fa-database"></i> {{:: 'user-federation' | translate}}</a></li>
+            <li data-ng-show="access.viewUsers" data-ng-class="(path[1] == 'user-storage' || path[2] == 'user-storage') && 'active'"><a href="#/realms/{{realm.realm}}/user-storage"><i class="fa fa-database"></i> {{:: 'user-storage' | translate}}</a></li>
             <li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'authentication' || path[2] == 'authentication') && 'active'"><a href="#/realms/{{realm.realm}}/authentication/flows"><i class="fa fa-lock"></i> {{:: 'authentication' | translate}}</a></li>
         </ul>
     </div>