Merge pull request #3105 from patriot1burke/master

component model
This commit is contained in:
Bill Burke 2016-08-02 09:28:55 -04:00 committed by GitHub
commit 7f08717dfb
10 changed files with 132 additions and 5 deletions

View file

@ -206,6 +206,18 @@ public class RealmAdminResource {
return resource; return resource;
} }
/**
* 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 * base path for managing realm-level roles of this realm
* *

View file

@ -52,7 +52,7 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
this.session = session; this.session = session;
this.model = model; this.model = model;
this.userPasswords = userPasswords; this.userPasswords = userPasswords;
this.federatedStorageEnabled = model.getConfig().containsKey("USER_FEDERATED_STORAGE"); this.federatedStorageEnabled = model.getConfig().containsKey("federatedStorage") && Boolean.valueOf(model.getConfig().getFirst("federatedStorage")).booleanValue();
} }

View file

@ -20,9 +20,12 @@ import org.keycloak.Config;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.storage.UserStorageProviderFactory; import org.keycloak.storage.UserStorageProviderFactory;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties; import java.util.Properties;
/** /**
@ -38,7 +41,7 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) { public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
Properties props = new Properties(); Properties props = new Properties();
try { try {
props.load(getClass().getResourceAsStream(model.getConfig().getFirst("property.file"))); props.load(getClass().getResourceAsStream(model.getConfig().getFirst("propertyFile")));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -50,6 +53,19 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
return PROVIDER_ID; 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 @Override
public void init(Config.Scope config) { public void init(Config.Scope config) {

View file

@ -67,15 +67,15 @@ public class UserStorageTest {
model.setPriority(1); model.setPriority(1);
model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID); model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
model.setParentId(appRealm.getId()); 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); appRealm.addComponentModel(model);
model = new UserStorageProviderModel(); model = new UserStorageProviderModel();
model.setName("user-props"); model.setName("user-props");
model.setPriority(2); model.setPriority(2);
model.setParentId(appRealm.getId()); model.setParentId(appRealm.getId());
model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID); model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
model.getConfig().putSingle("property.file", "/storage-test/user-password.properties"); model.getConfig().putSingle("propertyFile", "/storage-test/user-password.properties");
model.getConfig().putSingle("USER_FEDERATED_STORAGE", "true"); model.getConfig().putSingle("federatedStorage", "true");
appRealm.addComponentModel(model); appRealm.addComponentModel(model);
} }
}); });

View file

@ -585,6 +585,7 @@ add-client-template=Add client template
manage=Manage manage=Manage
authentication=Authentication authentication=Authentication
user-federation=User Federation user-federation=User Federation
user-storage=User Storage
events=Events events=Events
realm-settings=Realm Settings realm-settings=Realm Settings
configure=Configure configure=Configure
@ -687,6 +688,7 @@ create-user-federation-mapper=Create user federation mapper
add-user-federation-mapper=Add user federation mapper add-user-federation-mapper=Add user federation mapper
provider-name=Provider Name provider-name=Provider Name
no-user-federation-providers-configured=No user federation providers configured 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=Add identity provider
add-identity-provider-link=Add identity provider link add-identity-provider-link=Add identity provider link
identity-provider=Identity Provider identity-provider=Identity Provider

View file

@ -1338,6 +1338,18 @@ module.config([ '$routeProvider', function($routeProvider) {
}, },
controller : 'RealmSessionStatsCtrl' 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', { .when('/realms/:realm/user-federation', {
templateUrl : resourceUrl + '/partials/user-federation.html', templateUrl : resourceUrl + '/partials/user-federation.html',
resolve : { resolve : {

View file

@ -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) { module.controller('UserFederationCtrl', function($scope, $location, $route, realm, UserFederationProviders, UserFederationInstances, Notifications, Dialog) {
console.log('UserFederationCtrl ++++****'); console.log('UserFederationCtrl ++++****');
$scope.realm = realm; $scope.realm = realm;

View file

@ -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'
}
});
});

View file

@ -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>

View file

@ -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.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.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-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> <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> </ul>
</div> </div>