commit
7f08717dfb
10 changed files with 132 additions and 5 deletions
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 : {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue