ldap port admin console
This commit is contained in:
parent
f138eecc27
commit
4880c0443c
14 changed files with 1011 additions and 15 deletions
|
@ -19,6 +19,7 @@ package org.keycloak.storage.ldap;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.common.constants.KerberosConstants;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.component.ComponentValidationException;
|
||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||
|
@ -33,6 +34,8 @@ import org.keycloak.models.ModelException;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
@ -83,10 +86,115 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
|
|||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LDAPStorageProviderFactory.class);
|
||||
public static final String PROVIDER_NAME = "ldap2";//LDAPConstants.LDAP_PROVIDER;
|
||||
public static final String PROVIDER_NAME = LDAPConstants.LDAP_PROVIDER;
|
||||
|
||||
private LDAPIdentityStoreRegistry ldapStoreRegistry;
|
||||
|
||||
protected static final List<ProviderConfigProperty> configProperties;
|
||||
|
||||
static {
|
||||
configProperties = getConfigProps(null);
|
||||
}
|
||||
|
||||
private static List<ProviderConfigProperty> getConfigProps(ComponentModel parent) {
|
||||
boolean readOnly = false;
|
||||
if (parent != null) {
|
||||
LDAPConfig config = new LDAPConfig(parent.getConfig());
|
||||
readOnly = config.getEditMode() != LDAPStorageProviderFactory.EditMode.WRITABLE;
|
||||
}
|
||||
|
||||
|
||||
return ProviderConfigurationBuilder.create()
|
||||
.property().name(LDAPConstants.EDIT_MODE)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.SYNC_REGISTRATIONS)
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||
.defaultValue("false")
|
||||
.add()
|
||||
.property().name(LDAPConstants.VENDOR)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.USERNAME_LDAP_ATTRIBUTE)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.RDN_LDAP_ATTRIBUTE)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.UUID_LDAP_ATTRIBUTE)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.USER_OBJECT_CLASSES)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.CONNECTION_URL)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.USERS_DN)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.AUTH_TYPE)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.defaultValue("simple")
|
||||
.add()
|
||||
.property().name(LDAPConstants.BIND_DN)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.BIND_CREDENTIAL)
|
||||
.type(ProviderConfigProperty.PASSWORD)
|
||||
.secret(true)
|
||||
.add()
|
||||
.property().name(LDAPConstants.CUSTOM_USER_SEARCH_FILTER)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(LDAPConstants.SEARCH_SCOPE)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.defaultValue("1")
|
||||
.add()
|
||||
.property().name(LDAPConstants.USE_TRUSTSTORE_SPI)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.defaultValue("ldapsOnly")
|
||||
.add()
|
||||
.property().name(LDAPConstants.CONNECTION_POOLING)
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||
.defaultValue("true")
|
||||
.add()
|
||||
.property().name(LDAPConstants.PAGINATION)
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||
.defaultValue("true")
|
||||
.add()
|
||||
.property().name(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION)
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||
.defaultValue("false")
|
||||
.add()
|
||||
.property().name(KerberosConstants.SERVER_PRINCIPAL)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(KerberosConstants.KEYTAB)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(KerberosConstants.KERBEROS_REALM)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.property().name(KerberosConstants.DEBUG)
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||
.defaultValue("false")
|
||||
.add()
|
||||
.property().name(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION)
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||
.defaultValue("false")
|
||||
.add()
|
||||
.property().name(KerberosConstants.SERVER_PRINCIPAL)
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LDAPStorageProvider create(KeycloakSession session, ComponentModel model) {
|
||||
LDAPIdentityStore ldapIdentityStore = this.ldapStoreRegistry.getLdapStore(model);
|
||||
|
|
|
@ -27,7 +27,9 @@ import org.keycloak.provider.ProviderConfigProperty;
|
|||
import org.keycloak.representations.idm.UserFederationMapperSyncConfigRepresentation;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -60,8 +62,12 @@ public abstract class AbstractLDAPStorageMapperFactory implements LDAPStorageMap
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserFederationMapperSyncConfigRepresentation getSyncConfig() {
|
||||
return new UserFederationMapperSyncConfigRepresentation(false, null, false, null);
|
||||
public Map<String, Object> getTypeMetadata() {
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("fedToKeycloakSyncSupported", false);
|
||||
metadata.put("keycloakToFedSyncSupported", false);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,8 +44,6 @@ public interface LDAPStorageMapperFactory<T extends LDAPStorageMapper> extends S
|
|||
*/
|
||||
T create(KeycloakSession session, ComponentModel model);
|
||||
|
||||
UserFederationMapperSyncConfigRepresentation getSyncConfig();
|
||||
|
||||
/**
|
||||
* This is the name of the provider and will be showed in the admin console as an option.
|
||||
*
|
||||
|
|
|
@ -176,10 +176,17 @@ public class GroupLDAPStorageMapperFactory extends AbstractLDAPStorageMapperFact
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserFederationMapperSyncConfigRepresentation getSyncConfig() {
|
||||
return new UserFederationMapperSyncConfigRepresentation(true, "sync-ldap-groups-to-keycloak", true, "sync-keycloak-groups-to-ldap");
|
||||
public Map<String, Object> getTypeMetadata() {
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("fedToKeycloakSyncSupported", true);
|
||||
metadata.put("fedToKeycloakSyncMessage", "sync-ldap-groups-to-keycloak");
|
||||
metadata.put("keycloakToFedSyncSupported", true);
|
||||
metadata.put("keycloakToFedSyncMessage", "sync-keycloak-groups-to-ldap");
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
|
||||
checkMandatoryConfigAttribute(GroupMapperConfig.GROUPS_DN, "LDAP Groups DN", config);
|
||||
|
|
|
@ -168,10 +168,17 @@ public class RoleLDAPStorageMapperFactory extends AbstractLDAPStorageMapperFacto
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserFederationMapperSyncConfigRepresentation getSyncConfig() {
|
||||
return new UserFederationMapperSyncConfigRepresentation(true, "sync-ldap-roles-to-keycloak", true, "sync-keycloak-roles-to-ldap");
|
||||
public Map<String, Object> getTypeMetadata() {
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("fedToKeycloakSyncSupported", true);
|
||||
metadata.put("fedToKeycloakSyncMessage", "sync-ldap-roles-to-keycloak");
|
||||
metadata.put("keycloakToFedSyncSupported", true);
|
||||
metadata.put("keycloakToFedSyncMessage", "sync-keycloak-roles-to-ldap");
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
|
||||
checkMandatoryConfigAttribute(RoleMapperConfig.ROLES_DN, "LDAP Roles DN", config);
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.provider.ProviderFactory;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -55,5 +56,17 @@ public interface ComponentFactory<CreatedType, ProviderType extends Provider> ex
|
|||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is metadata about this component type. Its really configuration information about the component type and not
|
||||
* an individual instance
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default
|
||||
Map<String, Object> getTypeMetadata() {
|
||||
return Collections.EMPTY_MAP;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.provider.ProviderFactory;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Useful when you want to describe config properties that are effected by the parent ComponentModel
|
||||
|
@ -37,4 +38,16 @@ public interface SubComponentFactory<CreatedType, ProviderType extends Provider>
|
|||
List<ProviderConfigProperty> getConfigProperties(RealmModel realm, ComponentModel parent) {
|
||||
return getConfigProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is metadata about this component type. Its really configuration information about the component type and not
|
||||
* an individual instance
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default Map<String, Object> getTypeMetadata(RealmModel realm, ComponentModel parent) {
|
||||
return getTypeMetadata();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,10 +26,13 @@ import org.keycloak.models.KeycloakSessionFactory;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
import org.keycloak.storage.user.ImportSynchronization;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -108,4 +111,14 @@ public interface UserStorageProviderFactory<T extends UserStorageProvider> exten
|
|||
List<ProviderConfigProperty> getCommonProviderConfigProperties() {
|
||||
return UserStorageProviderSpi.commonConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
default
|
||||
Map<String, Object> getTypeMetadata() {
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
if (this instanceof ImportSynchronization) {
|
||||
metadata.put("synchronizable", true);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,8 @@ public class UserStorageProviderSpi implements Spi {
|
|||
.property()
|
||||
.name("lastSync").type(ProviderConfigProperty.STRING_TYPE).add()
|
||||
.property()
|
||||
.name("batchSizeForSync").type(ProviderConfigProperty.STRING_TYPE).add()
|
||||
.property()
|
||||
.name("importEnabled").type(ProviderConfigProperty.BOOLEAN_TYPE).add()
|
||||
.property()
|
||||
.name("cachePolicy").type(ProviderConfigProperty.STRING_TYPE).add()
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.jboss.logging.Logger;
|
|||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.component.ComponentFactory;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.component.ComponentValidationException;
|
||||
import org.keycloak.component.SubComponentFactory;
|
||||
|
@ -59,6 +60,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -207,7 +209,7 @@ public class ComponentResource {
|
|||
@Path("{id}/sub-component-config")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<ConfigPropertyRepresentation> getSubcomponentConfig(@PathParam("id") String id, @QueryParam("type") String providerType, @QueryParam("id") String providerId) {
|
||||
public ComponentTypeRepresentation getSubcomponentConfig(@PathParam("id") String id, @QueryParam("type") String providerType, @QueryParam("id") String providerId) {
|
||||
auth.requireView();
|
||||
ComponentModel parent = realm.getComponent(id);
|
||||
if (parent == null) {
|
||||
|
@ -224,9 +226,29 @@ public class ComponentResource {
|
|||
throw new NotFoundException("Could not find subcomponent factory");
|
||||
|
||||
}
|
||||
if (!(factory instanceof SubComponentFactory)) return Collections.EMPTY_LIST;
|
||||
List<ProviderConfigProperty> props = ((SubComponentFactory)factory).getConfigProperties(realm, parent);
|
||||
return ModelToRepresentation.toRepresentation(props);
|
||||
if (!(factory instanceof ComponentFactory)) {
|
||||
throw new NotFoundException("Not a component factory");
|
||||
|
||||
}
|
||||
ComponentFactory componentFactory = (ComponentFactory)factory;
|
||||
ComponentTypeRepresentation rep = new ComponentTypeRepresentation();
|
||||
rep.setId(providerId);
|
||||
rep.setHelpText(componentFactory.getHelpText());
|
||||
List<ProviderConfigProperty> props = null;
|
||||
Map<String, Object> metadata = null;
|
||||
if (factory instanceof SubComponentFactory) {
|
||||
props = ((SubComponentFactory)factory).getConfigProperties(realm, parent);
|
||||
metadata = ((SubComponentFactory)factory).getTypeMetadata(realm, parent);
|
||||
|
||||
} else {
|
||||
props = componentFactory.getConfigProperties();
|
||||
metadata = componentFactory.getTypeMetadata();
|
||||
}
|
||||
|
||||
List<ConfigPropertyRepresentation> propReps = ModelToRepresentation.toRepresentation(props);
|
||||
rep.setProperties(propReps);
|
||||
rep.setMetadata(metadata);
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.services.resources.admin.info;
|
|||
import org.keycloak.broker.provider.IdentityProvider;
|
||||
import org.keycloak.broker.provider.IdentityProviderFactory;
|
||||
import org.keycloak.broker.social.SocialIdentityProvider;
|
||||
import org.keycloak.component.ComponentFactory;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
|
@ -136,8 +137,8 @@ public class ServerInfoAdminResource {
|
|||
List<ProviderConfigProperty> configProperties = configured.getConfigProperties();
|
||||
if (configProperties == null) configProperties = Collections.EMPTY_LIST;
|
||||
rep.setProperties(ModelToRepresentation.toRepresentation(configProperties));
|
||||
if (pi instanceof ImportSynchronization) {
|
||||
rep.getMetadata().put("synchronizable", true);
|
||||
if (pi instanceof ComponentFactory) {
|
||||
rep.setMetadata(((ComponentFactory)pi).getTypeMetadata());
|
||||
}
|
||||
List<ComponentTypeRepresentation> reps = info.getComponentTypes().get(spi.getProviderClass().getName());
|
||||
if (reps == null) {
|
||||
|
|
|
@ -1469,6 +1469,26 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'RealmSessionStatsCtrl'
|
||||
})
|
||||
.when('/create/user-storage/:realm/providers/ldap', {
|
||||
templateUrl : resourceUrl + '/partials/user-storage-ldap.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
instance : function() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
providerId : function($route) {
|
||||
return $route.current.params.provider;
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
},
|
||||
controller : 'LDAPUserStorageCtrl'
|
||||
})
|
||||
.when('/create/user-storage/:realm/providers/:provider', {
|
||||
templateUrl : resourceUrl + '/partials/user-storage-generic.html',
|
||||
resolve : {
|
||||
|
@ -1489,6 +1509,24 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'GenericUserStorageCtrl'
|
||||
})
|
||||
.when('/realms/:realm/user-storage/providers/ldap/:componentId', {
|
||||
templateUrl : resourceUrl + '/partials/user-storage-ldap.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
instance : function(ComponentLoader) {
|
||||
return ComponentLoader();
|
||||
},
|
||||
providerId : function($route) {
|
||||
return $route.current.params.provider;
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
}
|
||||
},
|
||||
controller : 'LDAPUserStorageCtrl'
|
||||
})
|
||||
.when('/realms/:realm/user-storage/providers/:provider/:componentId', {
|
||||
templateUrl : resourceUrl + '/partials/user-storage-generic.html',
|
||||
resolve : {
|
||||
|
|
|
@ -627,12 +627,14 @@ module.controller('UserFederationCtrl', function($scope, $location, $route, real
|
|||
for (var i = 0; i < $scope.providers.length; i++) {
|
||||
$scope.providers[i].isUserFederationProvider = false;
|
||||
}
|
||||
/*
|
||||
UserFederationProviders.query({realm: realm.realm}, function(data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
data[i].isUserFederationProvider = true;
|
||||
$scope.providers.push(data[i]);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
$scope.addProvider = function(provider) {
|
||||
console.log('Add provider: ' + provider.id);
|
||||
|
@ -1553,4 +1555,321 @@ module.controller('UserGroupMembershipCtrl', function($scope, $route, realm, gro
|
|||
|
||||
});
|
||||
|
||||
module.controller('LDAPUserStorageCtrl', function($scope, $location, Notifications, $route, Dialog, realm,
|
||||
serverInfo, instance, Components, UserStorageSync, RealmLDAPConnectionTester) {
|
||||
console.log('LDAPUserStorageCtrl');
|
||||
var providerId = 'ldap';
|
||||
console.log('providerId: ' + providerId);
|
||||
$scope.create = !instance.providerId;
|
||||
console.log('create: ' + $scope.create);
|
||||
var providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider'];
|
||||
console.log('providers length ' + providers.length);
|
||||
var providerFactory = null;
|
||||
for (var i = 0; i < providers.length; i++) {
|
||||
var p = providers[i];
|
||||
console.log('provider: ' + p.id);
|
||||
if (p.id == providerId) {
|
||||
$scope.providerFactory = p;
|
||||
providerFactory = p;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$scope.provider = instance;
|
||||
$scope.showSync = false;
|
||||
|
||||
$scope.ldapVendors = [
|
||||
{ "id": "ad", "name": "Active Directory" },
|
||||
{ "id": "rhds", "name": "Red Hat Directory Server" },
|
||||
{ "id": "tivoli", "name": "Tivoli" },
|
||||
{ "id": "edirectory", "name": "Novell eDirectory" },
|
||||
{ "id": "other", "name": "Other" }
|
||||
];
|
||||
|
||||
$scope.authTypes = [
|
||||
{ "id": "none", "name": "none" },
|
||||
{ "id": "simple", "name": "simple" }
|
||||
];
|
||||
|
||||
$scope.searchScopes = [
|
||||
{ "id": "1", "name": "One Level" },
|
||||
{ "id": "2", "name": "Subtree" }
|
||||
];
|
||||
|
||||
$scope.useTruststoreOptions = [
|
||||
{ "id": "always", "name": "Always" },
|
||||
{ "id": "ldapsOnly", "name": "Only for ldaps" },
|
||||
{ "id": "never", "name": "Never" }
|
||||
];
|
||||
|
||||
var DEFAULT_BATCH_SIZE = "1000";
|
||||
|
||||
|
||||
console.log("providerFactory: " + providerFactory.id);
|
||||
|
||||
function initUserStorageSettings() {
|
||||
if ($scope.create) {
|
||||
instance.name = 'ldap';
|
||||
instance.providerId = 'ldap';
|
||||
instance.providerType = 'org.keycloak.storage.UserStorageProvider';
|
||||
instance.parentId = realm.id;
|
||||
instance.config = {
|
||||
|
||||
};
|
||||
instance.config['priority'] = ["0"];
|
||||
|
||||
$scope.fullSyncEnabled = false;
|
||||
$scope.changedSyncEnabled = false;
|
||||
instance.config['fullSyncPeriod'] = ['-1'];
|
||||
instance.config['changedSyncPeriod'] = ['-1'];
|
||||
instance.config['cachePolicy'] = ['DEFAULT'];
|
||||
instance.config['evictionDay'] = [''];
|
||||
instance.config['evictionHour'] = [''];
|
||||
instance.config['evictionMinute'] = [''];
|
||||
instance.config['maxLifespan'] = [''];
|
||||
instance.config['batchSizeForSync'] = [DEFAULT_BATCH_SIZE];
|
||||
|
||||
if (providerFactory.properties) {
|
||||
|
||||
for (var i = 0; i < providerFactory.properties.length; i++) {
|
||||
var configProperty = providerFactory.properties[i];
|
||||
if (configProperty.defaultValue) {
|
||||
instance.config[configProperty.name] = [configProperty.defaultValue];
|
||||
} else {
|
||||
instance.config[configProperty.name] = [''];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
$scope.fullSyncEnabled = (instance.config['fullSyncPeriod'] && instance.config['fullSyncPeriod'][0] > 0);
|
||||
$scope.changedSyncEnabled = (instance.config['changedSyncPeriod'] && instance.config['changedSyncPeriod'][0]> 0);
|
||||
if (!instance.config['fullSyncPeriod']) {
|
||||
console.log('setting to -1');
|
||||
instance.config['fullSyncPeriod'] = ['-1'];
|
||||
|
||||
}
|
||||
if (!instance.config['changedSyncPeriod']) {
|
||||
console.log('setting to -1');
|
||||
instance.config['changedSyncPeriod'] = ['-1'];
|
||||
|
||||
}
|
||||
if (!instance.config['cachePolicy']) {
|
||||
instance.config['cachePolicy'] = ['DEFAULT'];
|
||||
|
||||
}
|
||||
if (!instance.config['evictionDay']) {
|
||||
instance.config['evictionDay'] = [''];
|
||||
|
||||
}
|
||||
if (!instance.config['evictionHour']) {
|
||||
instance.config['evictionHour'] = [''];
|
||||
|
||||
}
|
||||
if (!instance.config['evictionMinute']) {
|
||||
instance.config['evictionMinute'] = [''];
|
||||
|
||||
}
|
||||
if (!instance.config['maxLifespan']) {
|
||||
instance.config['maxLifespan'] = [''];
|
||||
|
||||
}
|
||||
if (!instance.config['priority']) {
|
||||
instance.config['priority'] = ['0'];
|
||||
}
|
||||
|
||||
if (providerFactory.properties) {
|
||||
|
||||
for (var i = 0; i < providerFactory.properties.length; i++) {
|
||||
var configProperty = providerFactory.properties[i];
|
||||
if (!instance.config[configProperty.name]) {
|
||||
if (configProperty.defaultValue) {
|
||||
instance.config[configProperty.name] = [configProperty.defaultValue];
|
||||
} else {
|
||||
instance.config[configProperty.name] = [''];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (var i=0 ; i<$scope.ldapVendors.length ; i++) {
|
||||
if ($scope.ldapVendors[i].id === instance.config['vendor'][0]) {
|
||||
$scope.vendorName = $scope.ldapVendors[i].name;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (instance.config && instance.config['importEnabled']) {
|
||||
$scope.showSync = instance.config['importEnabled'][0] == 'true';
|
||||
} else {
|
||||
$scope.showSync = true;
|
||||
}
|
||||
|
||||
$scope.changed = false;
|
||||
}
|
||||
|
||||
initUserStorageSettings();
|
||||
$scope.instance = angular.copy(instance);
|
||||
$scope.realm = realm;
|
||||
|
||||
$scope.$watch('instance', function() {
|
||||
if (!angular.equals($scope.instance, instance)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
|
||||
if (!angular.equals($scope.instance.config['vendor'][0], $scope.lastVendor)) {
|
||||
console.log("LDAP vendor changed");
|
||||
$scope.lastVendor = $scope.instance.config['vendor'][0];
|
||||
|
||||
if ($scope.lastVendor === "ad") {
|
||||
$scope.instance.config['usernameLDAPAttribute'][0] = "cn";
|
||||
$scope.instance.config['userObjectClasses'][0] = "person, organizationalPerson, user";
|
||||
} else {
|
||||
$scope.instance.config['usernameLDAPAttribute'][0] = "uid";
|
||||
$scope.instance.config['userObjectClasses'][0] = "inetOrgPerson, organizationalPerson";
|
||||
}
|
||||
|
||||
$scope.instance.config['rdnLDAPAttribute'][0] = $scope.instance.config['usernameLDAPAttribute'][0];
|
||||
|
||||
var vendorToUUID = {
|
||||
rhds: "nsuniqueid",
|
||||
tivoli: "uniqueidentifier",
|
||||
edirectory: "guid",
|
||||
ad: "objectGUID",
|
||||
other: "entryUUID"
|
||||
};
|
||||
$scope.instance.config['uuidLDAPAttribute'][0] = vendorToUUID[$scope.lastVendor];
|
||||
}
|
||||
|
||||
|
||||
}, true);
|
||||
|
||||
$scope.$watch('fullSyncEnabled', function(newVal, oldVal) {
|
||||
if (oldVal == newVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.instance.config['fullSyncPeriod'][0] = $scope.fullSyncEnabled ? "604800" : "-1";
|
||||
$scope.changed = true;
|
||||
});
|
||||
|
||||
$scope.$watch('changedSyncEnabled', function(newVal, oldVal) {
|
||||
if (oldVal == newVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.instance.config['changedSyncPeriod'][0] = $scope.changedSyncEnabled ? "86400" : "-1";
|
||||
$scope.changed = true;
|
||||
});
|
||||
|
||||
|
||||
$scope.save = function() {
|
||||
$scope.changed = false;
|
||||
if (!parseInt($scope.instance.config['batchSizeForSync'[0]])) {
|
||||
$scope.instance.config['batchSizeForSync'][0] = DEFAULT_BATCH_SIZE;
|
||||
} else {
|
||||
$scope.instance.config['batchSizeForSync'][0] = parseInt($scope.instance.config.batchSizeForSync).toString();
|
||||
}
|
||||
|
||||
if ($scope.create) {
|
||||
Components.save({realm: realm.realm}, $scope.instance, function (data, headers) {
|
||||
var l = headers().location;
|
||||
var id = l.substring(l.lastIndexOf("/") + 1);
|
||||
|
||||
$location.url("/realms/" + realm.realm + "/user-storage/providers/" + $scope.instance.providerId + "/" + id);
|
||||
Notifications.success("The provider has been created.");
|
||||
}, function (errorResponse) {
|
||||
if (errorResponse.data && errorResponse.data['error_description']) {
|
||||
Notifications.error(errorResponse.data['error_description']);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Components.update({realm: realm.realm,
|
||||
componentId: instance.id
|
||||
},
|
||||
$scope.instance, function () {
|
||||
$route.reload();
|
||||
Notifications.success("The provider has been updated.");
|
||||
}, function (errorResponse) {
|
||||
if (errorResponse.data && errorResponse.data['error_description']) {
|
||||
Notifications.error(errorResponse.data['error_description']);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
initUserStorageSettings();
|
||||
$scope.instance = angular.copy(instance);
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
if ($scope.create) {
|
||||
$location.url("/realms/" + realm.realm + "/user-storage");
|
||||
} else {
|
||||
$route.reload();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.triggerFullSync = function() {
|
||||
console.log('GenericCtrl: triggerFullSync');
|
||||
triggerSync('triggerFullSync');
|
||||
}
|
||||
|
||||
$scope.triggerChangedUsersSync = function() {
|
||||
console.log('GenericCtrl: triggerChangedUsersSync');
|
||||
triggerSync('triggerChangedUsersSync');
|
||||
}
|
||||
|
||||
function triggerSync(action) {
|
||||
UserStorageSync.save({ action: action, realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) {
|
||||
$route.reload();
|
||||
Notifications.success("Sync of users finished successfully. " + syncResult.status);
|
||||
}, function() {
|
||||
$route.reload();
|
||||
Notifications.error("Error during sync of users");
|
||||
});
|
||||
}
|
||||
|
||||
var initConnectionTest = function(testAction, ldapConfig) {
|
||||
return {
|
||||
action: testAction,
|
||||
realm: $scope.realm.realm,
|
||||
connectionUrl: ldapConfig.connectionUrl,
|
||||
bindDn: ldapConfig.bindDn,
|
||||
bindCredential: ldapConfig.bindCredential,
|
||||
useTruststoreSpi: ldapConfig.useTruststoreSpi
|
||||
};
|
||||
};
|
||||
|
||||
$scope.testConnection = function() {
|
||||
console.log('LDAPCtrl: testConnection');
|
||||
RealmLDAPConnectionTester.get(initConnectionTest("testConnection", $scope.instance.config), function() {
|
||||
Notifications.success("LDAP connection successful.");
|
||||
}, function() {
|
||||
Notifications.error("Error when trying to connect to LDAP. See server.log for details.");
|
||||
});
|
||||
}
|
||||
|
||||
$scope.testAuthentication = function() {
|
||||
console.log('LDAPCtrl: testAuthentication');
|
||||
RealmLDAPConnectionTester.get(initConnectionTest("testAuthentication", $scope.instance.config), function() {
|
||||
Notifications.success("LDAP authentication successful.");
|
||||
}, function() {
|
||||
Notifications.error("LDAP authentication failed. See server.log for details");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,449 @@
|
|||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/user-federation">{{:: 'user-federation' | translate}}</a></li>
|
||||
<li data-ng-hide="create">{{instance.name|capitalize}}</li>
|
||||
<li data-ng-show="create">{{:: 'add-user-storage-provider' | translate}}</li>
|
||||
</ol>
|
||||
|
||||
<kc-tabs-user-storage></kc-tabs-user-storage>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<input type="text" readonly value="this is not a login form" style="display: none;">
|
||||
<input type="password" readonly value="this is not a login form" style="display: none;">
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">{{:: 'required-settings' | translate}}</span></legend>
|
||||
<div class="form-group clearfix" data-ng-show="!create">
|
||||
<label class="col-md-2 control-label" for="providerId">{{:: 'provider-id' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="providerId" type="text" ng-model="instance.id" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="consoleDisplayName">{{:: 'console-display-name' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="consoleDisplayName" type="text" ng-model="instance.name" placeholder="{{:: 'defaults-to-id' | translate}}">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'console-display-name.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="priority">{{:: 'priority' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="priority" type="text" ng-model="instance.config['priority'][0]">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'priority.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="editMode">{{:: 'edit-mode' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<div>
|
||||
<select class="form-control" id="editMode"
|
||||
ng-model="instance.config['editMode'][0]">
|
||||
<option>READ_ONLY</option>
|
||||
<option>WRITABLE</option>
|
||||
<option>UNSYNCED</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.edit-mode.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-md-2 control-label" for="syncRegistrations">{{:: 'sync-registrations' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['syncRegistrations'][0]" name="syncRegistrations" id="syncRegistrations" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.sync-registrations.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="vendor"><span class="required">*</span> {{:: 'vendor' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<div data-ng-show="create">
|
||||
<select class="form-control" id="vendor"
|
||||
ng-model="instance.config['vendor'][0]"
|
||||
ng-options="vendor.id as vendor.name for vendor in ldapVendors"
|
||||
required>
|
||||
</select>
|
||||
</div>
|
||||
<div data-ng-show="!create">
|
||||
<input class="form-control" id="vendor-ro" type="text" ng-model="vendorName" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.vendor.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="usernameLDAPAttribute"><span class="required">*</span> {{:: 'username-ldap-attribute' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="usernameLDAPAttribute" type="text" ng-model="instance.config['usernameLDAPAttribute'][0]" placeholder="{{:: 'ldap-attribute-name-for-username' | translate}}" required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'username-ldap-attribute.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="rdnLDAPAttribute"><span class="required">*</span> {{:: 'rdn-ldap-attribute' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="rdnLDAPAttribute" type="text" ng-model="instance.config['rdnLDAPAttribute'][0]" placeholder="{{:: 'ldap-attribute-name-for-user-rdn' | translate}}" required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'rdn-ldap-attribute.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="uuidLDAPAttribute"><span class="required">*</span> {{:: 'uuid-ldap-attribute' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="uuidLDAPAttribute" type="text" ng-model="instance.config['uuidLDAPAttribute'][0]" placeholder="{{:: 'ldap-attribute-name-for-uuid' | translate}}" required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'uuid-ldap-attribute.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="userObjectClasses"><span class="required">*</span> {{:: 'user-object-classes' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="userObjectClasses" type="text" ng-model="instance.config['userObjectClasses'][0]" placeholder="{{:: 'ldap-user-object-classes.placeholder' | translate}}" required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.user-object-classes.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="ldapConnectionUrl"><span class="required">*</span> {{:: 'connection-url' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="ldapConnectionUrl" type="text" ng-model="instance.config['connectionUrl'][0]" placeholder="{{:: 'ldap-connection-url' | translate}}" required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.connection-url.tooltip' | translate}}</kc-tooltip>
|
||||
<div class="col-sm-4" data-ng-show="access.manageRealm">
|
||||
<a class="btn btn-primary" data-ng-click="testConnection()">{{:: 'test-connection' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="ldapUsersDn"><span class="required">*</span> {{:: 'users-dn' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="ldapUsersDn" type="text" ng-model="instance.config['usersDn'][0]" placeholder="{{:: 'ldap-users-dn' | translate}}" required>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.users-dn.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="authType"><span class="required">*</span> {{:: 'authentication-type' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<div>
|
||||
<select class="form-control" id="authType"
|
||||
ng-model="instance.config['authType'][0]"
|
||||
ng-options="authType.id as authType.name for authType in authTypes"
|
||||
required>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.authentication-type.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-hide="instance.config['authType'][0] == 'none'">
|
||||
<label class="col-md-2 control-label" for="ldapBindDn"><span class="required">*</span> {{:: 'bind-dn' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="ldapBindDn" type="text" ng-model="instance.config['bindDn'][0]" placeholder="{{:: 'ldap-bind-dn' | translate}}" data-ng-required="instance.config['authType'][0] != 'none'">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.bind-dn.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-hide="instance.config['authType'][0] == 'none'">
|
||||
<label class="col-md-2 control-label" for="ldapBindCredential"><span class="required">*</span> {{:: 'bind-credential' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="ldapBindCredential" type="password" ng-model="instance.config['bindCredential'][0]" placeholder="{{:: 'ldap-bind-credentials' | translate}}" data-ng-required="instance.config['authType'][0] != 'none'">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.bind-credential.tooltip' | translate}}</kc-tooltip>
|
||||
<div class="col-sm-4" data-ng-show="access.manageRealm">
|
||||
<a class="btn btn-primary" data-ng-click="testAuthentication()">{{:: 'test-authentication' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="customUserSearchFilter">{{:: 'custom-user-ldap-filter' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="customUserSearchFilter" type="text" ng-model="instance.config['customUserSearchFilter'][0]" placeholder="{{:: 'ldap-filter' | translate}}">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.custom-user-ldap-filter.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="searchScope">{{:: 'search-scope' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<div>
|
||||
<select class="form-control" id="searchScope"
|
||||
ng-model="instance.config['searchScope'][0]"
|
||||
ng-options="searchScope.id as searchScope.name for searchScope in searchScopes"
|
||||
required>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.search-scope.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="useTruststoreSpi">{{:: 'use-truststore-spi' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<div>
|
||||
<select class="form-control" id="useTruststoreSpi"
|
||||
ng-model="instance.config['useTruststoreSpi'][0]"
|
||||
ng-options="useTruststoreSpi.id as useTruststoreSpi.name for useTruststoreSpi in useTruststoreOptions"
|
||||
required>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.use-truststore-spi.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="connectionPooling">{{:: 'connection-pooling' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['connectionPooling'][0]" name="connectionPooling" id="connectionPooling" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.connection-pooling.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="pagination">{{:: 'pagination' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['pagination'][0]" name="pagination" id="pagination" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.pagination.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">{{:: 'kerberos-integration' | translate}}</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="allowKerberosAuthentication">{{:: 'allow-kerberos-authentication' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['allowKerberosAuthentication'][0]" name="allowKerberosAuthentication" id="allowKerberosAuthentication" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.allow-kerberos-authentication.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
<label class="col-md-2 control-label" for="kerberosRealm"><span class="required">*</span> {{:: 'kerberos-realm' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="kerberosRealm" type="text" ng-model="instance.config['kerberosRealm'][0]" ng-required="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'kerberos-realm.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
<label class="col-md-2 control-label" for="serverPrincipal"><span class="required">*</span> {{:: 'server-principal' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="serverPrincipal" type="text" ng-model="instance.config['serverPrincipal'][0]" ng-required="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'server-principal.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
<label class="col-md-2 control-label" for="keyTab"><span class="required">*</span> {{:: 'keytab' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="keyTab" type="text" ng-model="instance.config['keyTab'][0]" ng-required="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'keytab.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="instance.config['allowKerberosAuthentication'][0] == 'true'">
|
||||
<label class="col-md-2 control-label" for="debug">{{:: 'debug' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['debug'][0]" name="debug" id="debug" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'debug.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="instance.config['allowKerberosAuthentication'][0]">
|
||||
<label class="col-md-2 control-label" for="useKerberosForPasswordAuthentication">{{:: 'use-kerberos-for-password-authentication' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['useKerberosForPasswordAuthentication'][0]" id="useKerberosForPasswordAuthentication" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.use-kerberos-for-password-authentication.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">{{:: 'sync-settings' | translate}}</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="batchSizeForSync">{{:: 'batch-size' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="text" ng-model="instance.config['batchSizeForSync'][0]" id="batchSizeForSync" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.batch-size.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="fullSyncEnabled">{{:: 'periodic-full-sync' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="fullSyncEnabled" name="fullSyncEnabled" id="fullSyncEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.periodic-full-sync.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="fullSyncEnabled">
|
||||
<label class="col-md-2 control-label" for="fullSyncPeriod">{{:: 'full-sync-period' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="text" ng-model="instance.config['fullSyncPeriod'][0]" id="fullSyncPeriod" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'full-sync-period.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="changedSyncEnabled">{{:: 'periodic-changed-users-sync' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="changedSyncEnabled" name="changedSyncEnabled" id="changedSyncEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.periodic-changed-users-sync.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="changedSyncEnabled">
|
||||
<label class="col-md-2 control-label" for="changedSyncPeriod">{{:: 'changed-users-sync-period' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="text" ng-model="instance.config['changedSyncPeriod'][0]" id="changedSyncPeriod" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'ldap.changed-users-sync-period.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">{{:: 'user-storage-cache-policy' | translate}}</span></legend>
|
||||
<div class="form-group">
|
||||
<label for="cachePolicy" class="col-md-2 control-label">{{:: 'userStorage.cachePolicy' | translate}}</label>
|
||||
<div class="col-md-2">
|
||||
<div>
|
||||
<select id="cachePolicy" ng-model="instance.config['cachePolicy'][0]" class="form-control">
|
||||
<option value="DEFAULT">{{:: 'userStorage.cachePolicy.option.DEFAULT' | translate}}</option>
|
||||
<option value="EVICT_DAILY">{{:: 'userStorage.cachePolicy.option.EVICT_DAILY' | translate}}</option>
|
||||
<option value="EVICT_WEEKLY">{{:: 'userStorage.cachePolicy.option.EVICT_WEEKLY' | translate}}</option>
|
||||
<option value="MAX_LIFESPAN">{{:: 'userStorage.cachePolicy.option.MAX_LIFESPAN' | translate}}</option>
|
||||
<option value="NO_CACHE">{{:: 'userStorage.cachePolicy.option.NO_CACHE' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'userStorage.cachePolicy.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="instance.config['cachePolicy'][0] == 'EVICT_WEEKLY'">
|
||||
<label for="evictionDay" class="col-md-2 control-label">{{:: 'userStorage.evictionDay' | translate}}</label>
|
||||
<div class="col-md-2">
|
||||
<div>
|
||||
<select id="evictionDay" ng-model="instance.config['evictionDay'][0]" class="form-control">
|
||||
<option value="1">{{:: 'Sunday' | translate}}</option>
|
||||
<option value="2">{{:: 'Monday' | translate}}</option>
|
||||
<option value="3">{{:: 'Tuesday' | translate}}</option>
|
||||
<option value="4">{{:: 'Wednesday' | translate}}</option>
|
||||
<option value="5">{{:: 'Thursday' | translate}}</option>
|
||||
<option value="6">{{:: 'Friday' | translate}}</option>
|
||||
<option value="7">{{:: 'Saturday' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'userStorage.cachePolicy.evictionDay.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="instance.config['cachePolicy'][0] == 'EVICT_WEEKLY' || instance.config['cachePolicy'][0] == 'EVICT_DAILY'">
|
||||
<label class="col-md-2 control-label" for="evictionHour">{{:: 'userStorage.cachePolicy.evictionHour' | translate}}</label>
|
||||
<div class="col-md-2">
|
||||
<div>
|
||||
<select id="evictionHour" ng-model="instance.config['evictionHour'][0]" class="form-control">
|
||||
<option value="0">00</option>
|
||||
<option value="1">01</option>
|
||||
<option value="2">02</option>
|
||||
<option value="3">03</option>
|
||||
<option value="4">04</option>
|
||||
<option value="5">05</option>
|
||||
<option value="6">06</option>
|
||||
<option value="7">07</option>
|
||||
<option value="8">08</option>
|
||||
<option value="9">09</option>
|
||||
<option value="10">10</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="14">14</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="17">17</option>
|
||||
<option value="18">18</option>
|
||||
<option value="19">19</option>
|
||||
<option value="20">20</option>
|
||||
<option value="21">21</option>
|
||||
<option value="22">22</option>
|
||||
<option value="23">23</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'userStorage.cachePolicy.evictionHour.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="instance.config['cachePolicy'][0] == 'EVICT_WEEKLY' || instance.config['cachePolicy'][0] == 'EVICT_DAILY'">
|
||||
<label class="col-md-2 control-label" for="evictionMinute">{{:: 'userStorage.cachePolicy.evictionMinute' | translate}}</label>
|
||||
<div class="col-md-2">
|
||||
<div>
|
||||
<select id="evictionMinute" ng-model="instance.config['evictionMinute'][0]" class="form-control">
|
||||
<option value="0">00</option>
|
||||
<option value="1">01</option>
|
||||
<option value="2">02</option>
|
||||
<option value="3">03</option>
|
||||
<option value="4">04</option>
|
||||
<option value="5">05</option>
|
||||
<option value="6">06</option>
|
||||
<option value="7">07</option>
|
||||
<option value="8">08</option>
|
||||
<option value="9">09</option>
|
||||
<option value="10">10</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="14">14</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="17">17</option>
|
||||
<option value="18">18</option>
|
||||
<option value="19">19</option>
|
||||
<option value="20">20</option>
|
||||
<option value="21">21</option>
|
||||
<option value="22">22</option>
|
||||
<option value="23">23</option>
|
||||
<option value="24">24</option>
|
||||
<option value="25">25</option>
|
||||
<option value="26">26</option>
|
||||
<option value="27">27</option>
|
||||
<option value="28">28</option>
|
||||
<option value="29">29</option>
|
||||
<option value="30">30</option>
|
||||
<option value="31">31</option>
|
||||
<option value="32">32</option>
|
||||
<option value="33">33</option>
|
||||
<option value="34">34</option>
|
||||
<option value="35">35</option>
|
||||
<option value="36">36</option>
|
||||
<option value="37">37</option>
|
||||
<option value="38">38</option>
|
||||
<option value="39">39</option>
|
||||
<option value="40">40</option>
|
||||
<option value="41">41</option>
|
||||
<option value="42">42</option>
|
||||
<option value="43">43</option>
|
||||
<option value="44">44</option>
|
||||
<option value="45">45</option>
|
||||
<option value="46">46</option>
|
||||
<option value="47">47</option>
|
||||
<option value="48">48</option>
|
||||
<option value="49">49</option>
|
||||
<option value="50">50</option>
|
||||
<option value="51">51</option>
|
||||
<option value="52">52</option>
|
||||
<option value="53">53</option>
|
||||
<option value="54">54</option>
|
||||
<option value="55">55</option>
|
||||
<option value="56">56</option>
|
||||
<option value="57">57</option>
|
||||
<option value="58">58</option>
|
||||
<option value="59">59</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'userStorage.cachePolicy.evictionMinute.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="instance.config['cachePolicy'][0] == 'MAX_LIFESPAN'">
|
||||
<label class="col-md-2 control-label" for="maxLifespan">{{:: 'userStorage.cachePolicy.maxLifespan' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="text" ng-model="instance.config['maxLifespan'][0]" id="maxLifespan" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'userStorage.cachePolicy.maxLifespan.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="create && access.manageRealm">
|
||||
<button kc-save>{{:: 'save' | translate}}</button>
|
||||
<button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="!create && access.manageRealm">
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
<button class="btn btn-primary" data-ng-click="triggerChangedUsersSync()" data-ng-hide="changed">{{:: 'synchronize-changed-users' | translate}}</button>
|
||||
<button class="btn btn-primary" data-ng-click="triggerFullSync()" data-ng-hide="changed">{{:: 'synchronize-all-users' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
Loading…
Reference in a new issue