commit
8cd8472003
15 changed files with 340 additions and 96 deletions
|
@ -42,11 +42,13 @@ public class MongoKeycloakTransaction implements KeycloakTransaction {
|
|||
} catch (MongoException e) {
|
||||
throw MongoStoreImpl.convertException(e);
|
||||
}
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
invocationContext.rollback();
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -101,24 +101,7 @@ public abstract class BasePropertiesFederationFactory implements UserFederationP
|
|||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
BasePropertiesFederationProvider federationProvider = (BasePropertiesFederationProvider)getInstance(session, model);
|
||||
Set<String> allUsernames = federationProvider.getProperties().stringPropertyNames();
|
||||
for (String username : allUsernames) {
|
||||
federationProvider.getUserByUsername(realm, username);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncChangedUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model, Date lastSync) {
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
public void run(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
UserProvider localProvider = session.userStorage();
|
||||
BasePropertiesFederationProvider federationProvider = (BasePropertiesFederationProvider)getInstance(session, model);
|
||||
Set<String> allUsernames = federationProvider.getProperties().stringPropertyNames();
|
||||
for (String username : allUsernames) {
|
||||
UserModel localUser = localProvider.getUserByUsername(username, realm);
|
||||
|
||||
|
@ -131,4 +114,9 @@ public abstract class BasePropertiesFederationFactory implements UserFederationP
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncChangedUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model, Date lastSync) {
|
||||
syncAllUsers(sessionFactory, realmId, model);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -356,25 +356,50 @@ module.controller('UserFederationCtrl', function($scope, $location, realm, UserF
|
|||
|
||||
});
|
||||
|
||||
module.controller('GenericUserFederationCtrl', function($scope, $location, Notifications, Dialog, realm, instance, providerFactory, UserFederationInstances) {
|
||||
module.controller('GenericUserFederationCtrl', function($scope, $location, Notifications, Dialog, realm, instance, providerFactory, UserFederationInstances, UserFederationSync) {
|
||||
console.log('GenericUserFederationCtrl');
|
||||
|
||||
$scope.instance = angular.copy(instance);
|
||||
$scope.create = !instance.providerName;
|
||||
$scope.providerFactory = providerFactory;
|
||||
|
||||
console.log("providerFactory: " + providerFactory.id);
|
||||
|
||||
if ($scope.create) {
|
||||
$scope.instance.providerName = providerFactory.id;
|
||||
$scope.instance.config = {};
|
||||
$scope.instance.priority = 0;
|
||||
function initFederationSettings() {
|
||||
if ($scope.create) {
|
||||
instance.providerName = providerFactory.id;
|
||||
instance.config = {};
|
||||
instance.priority = 0;
|
||||
$scope.fullSyncEnabled = false;
|
||||
$scope.changedSyncEnabled = false;
|
||||
} else {
|
||||
$scope.fullSyncEnabled = (instance.fullSyncPeriod && instance.fullSyncPeriod > 0);
|
||||
$scope.changedSyncEnabled = (instance.changedSyncPeriod && instance.changedSyncPeriod > 0);
|
||||
}
|
||||
|
||||
$scope.changed = false;
|
||||
}
|
||||
|
||||
initFederationSettings();
|
||||
$scope.instance = angular.copy(instance);
|
||||
$scope.realm = realm;
|
||||
|
||||
$scope.$watch('fullSyncEnabled', function(newVal, oldVal) {
|
||||
if (oldVal == newVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.changed = false;
|
||||
$scope.instance.fullSyncPeriod = $scope.fullSyncEnabled ? 604800 : -1;
|
||||
$scope.changed = true;
|
||||
});
|
||||
|
||||
$scope.$watch('changedSyncEnabled', function(newVal, oldVal) {
|
||||
if (oldVal == newVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.instance.changedSyncPeriod = $scope.changedSyncEnabled ? 86400 : -1;
|
||||
$scope.changed = true;
|
||||
});
|
||||
|
||||
$scope.$watch('instance', function() {
|
||||
if (!angular.equals($scope.instance, instance)) {
|
||||
|
@ -405,13 +430,8 @@ module.controller('GenericUserFederationCtrl', function($scope, $location, Notif
|
|||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
initFederationSettings();
|
||||
$scope.instance = angular.copy(instance);
|
||||
if ($scope.create) {
|
||||
$scope.instance.providerName = providerFactory.id;
|
||||
$scope.instance.config = {};
|
||||
$scope.instance.priority = 0;
|
||||
}
|
||||
$scope.changed = false;
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
|
@ -430,37 +450,70 @@ module.controller('GenericUserFederationCtrl', function($scope, $location, Notif
|
|||
});
|
||||
};
|
||||
|
||||
$scope.triggerFullSync = function() {
|
||||
console.log('GenericCtrl: triggerFullSync');
|
||||
triggerSync('triggerFullSync');
|
||||
}
|
||||
|
||||
$scope.triggerChangedUsersSync = function() {
|
||||
console.log('GenericCtrl: triggerChangedUsersSync');
|
||||
triggerSync('triggerChangedUsersSync');
|
||||
}
|
||||
|
||||
function triggerSync(action) {
|
||||
UserFederationSync.get({ action: action, realm: $scope.realm.realm, provider: $scope.instance.id }, function() {
|
||||
Notifications.success("Sync of users finished successfully");
|
||||
}, function() {
|
||||
Notifications.error("Error during sync of users");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog, realm, instance, UserFederationInstances, RealmLDAPConnectionTester) {
|
||||
module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog, realm, instance, UserFederationInstances, UserFederationSync, RealmLDAPConnectionTester) {
|
||||
console.log('LDAPCtrl');
|
||||
var DEFAULT_BATCH_SIZE = "1000";
|
||||
|
||||
$scope.instance = angular.copy(instance);
|
||||
$scope.create = !instance.providerName;
|
||||
|
||||
if ($scope.create) {
|
||||
$scope.instance.providerName = "ldap";
|
||||
$scope.instance.config = {};
|
||||
$scope.instance.priority = 0;
|
||||
$scope.syncRegistrations = false;
|
||||
function initFederationSettings() {
|
||||
if ($scope.create) {
|
||||
instance.providerName = "ldap";
|
||||
instance.config = {};
|
||||
instance.priority = 0;
|
||||
$scope.syncRegistrations = false;
|
||||
|
||||
$scope.userAccountControlsAfterPasswordUpdate = true;
|
||||
$scope.instance.config.userAccountControlsAfterPasswordUpdate = "true";
|
||||
$scope.userAccountControlsAfterPasswordUpdate = true;
|
||||
instance.config.userAccountControlsAfterPasswordUpdate = "true";
|
||||
|
||||
$scope.connectionPooling = true;
|
||||
$scope.instance.config.connectionPooling = "true";
|
||||
$scope.connectionPooling = true;
|
||||
instance.config.connectionPooling = "true";
|
||||
|
||||
$scope.pagination = true;
|
||||
$scope.instance.config.pagination = "true";
|
||||
} else {
|
||||
$scope.syncRegistrations = instance.config.syncRegistrations && instance.config.syncRegistrations == "true";
|
||||
$scope.userAccountControlsAfterPasswordUpdate = instance.config.userAccountControlsAfterPasswordUpdate && instance.config.userAccountControlsAfterPasswordUpdate == "true";
|
||||
$scope.connectionPooling = instance.config.connectionPooling && instance.config.connectionPooling == "true";
|
||||
$scope.pagination = instance.config.pagination && instance.config.pagination == "true";
|
||||
$scope.pagination = true;
|
||||
instance.config.pagination = "true";
|
||||
instance.config.batchSizeForSync = DEFAULT_BATCH_SIZE;
|
||||
|
||||
$scope.fullSyncEnabled = false;
|
||||
$scope.changedSyncEnabled = false;
|
||||
} else {
|
||||
$scope.syncRegistrations = instance.config.syncRegistrations && instance.config.syncRegistrations == "true";
|
||||
$scope.userAccountControlsAfterPasswordUpdate = instance.config.userAccountControlsAfterPasswordUpdate && instance.config.userAccountControlsAfterPasswordUpdate == "true";
|
||||
$scope.connectionPooling = instance.config.connectionPooling && instance.config.connectionPooling == "true";
|
||||
$scope.pagination = instance.config.pagination && instance.config.pagination == "true";
|
||||
if (!instance.config.batchSizeForSync) {
|
||||
instance.config.batchSizeForSync = DEFAULT_BATCH_SIZE;
|
||||
}
|
||||
$scope.fullSyncEnabled = (instance.fullSyncPeriod && instance.fullSyncPeriod > 0);
|
||||
$scope.changedSyncEnabled = (instance.changedSyncPeriod && instance.changedSyncPeriod > 0);
|
||||
}
|
||||
|
||||
$scope.changed = false;
|
||||
$scope.lastVendor = instance.config.vendor;
|
||||
}
|
||||
|
||||
initFederationSettings();
|
||||
$scope.instance = angular.copy(instance);
|
||||
|
||||
$scope.ldapVendors = [
|
||||
{ "id": "ad", "name": "Active Directory" },
|
||||
{ "id": "rhds", "name": "Red Hat Directory Server" },
|
||||
|
@ -473,11 +526,6 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
|||
|
||||
$scope.realm = realm;
|
||||
|
||||
|
||||
$scope.changed = false;
|
||||
|
||||
$scope.lastVendor = $scope.instance.config.vendor;
|
||||
|
||||
function watchBooleanProperty(propertyName) {
|
||||
$scope.$watch(propertyName, function() {
|
||||
if ($scope[propertyName]) {
|
||||
|
@ -493,6 +541,24 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
|||
watchBooleanProperty('connectionPooling');
|
||||
watchBooleanProperty('pagination');
|
||||
|
||||
$scope.$watch('fullSyncEnabled', function(newVal, oldVal) {
|
||||
if (oldVal == newVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.instance.fullSyncPeriod = $scope.fullSyncEnabled ? 604800 : -1;
|
||||
$scope.changed = true;
|
||||
});
|
||||
|
||||
$scope.$watch('changedSyncEnabled', function(newVal, oldVal) {
|
||||
if (oldVal == newVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.instance.changedSyncPeriod = $scope.changedSyncEnabled ? 86400 : -1;
|
||||
$scope.changed = true;
|
||||
});
|
||||
|
||||
$scope.$watch('instance', function() {
|
||||
if (!angular.equals($scope.instance, instance)) {
|
||||
$scope.changed = true;
|
||||
|
@ -514,6 +580,13 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
|||
|
||||
$scope.save = function() {
|
||||
$scope.changed = false;
|
||||
|
||||
if (!parseInt($scope.instance.config.batchSizeForSync)) {
|
||||
$scope.instance.config.batchSizeForSync = DEFAULT_BATCH_SIZE;
|
||||
} else {
|
||||
$scope.instance.config.batchSizeForSync = parseInt($scope.instance.config.batchSizeForSync).toString();
|
||||
}
|
||||
|
||||
if ($scope.create) {
|
||||
UserFederationInstances.save({realm: realm.realm}, $scope.instance, function () {
|
||||
$scope.changed = false;
|
||||
|
@ -534,15 +607,8 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
|||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
initFederationSettings();
|
||||
$scope.instance = angular.copy(instance);
|
||||
if ($scope.create) {
|
||||
$scope.instance.providerName = "ldap";
|
||||
$scope.instance.config = {};
|
||||
$scope.instance.priority = 0;
|
||||
$scope.syncRegistrations = false;
|
||||
}
|
||||
$scope.changed = false;
|
||||
$scope.lastVendor = $scope.instance.config.vendor;
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
|
@ -589,5 +655,24 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
|||
Notifications.error("LDAP authentication failed. See server.log for details");
|
||||
});
|
||||
}
|
||||
|
||||
$scope.triggerFullSync = function() {
|
||||
console.log('LDAPCtrl: triggerFullSync');
|
||||
triggerSync('triggerFullSync');
|
||||
}
|
||||
|
||||
$scope.triggerChangedUsersSync = function() {
|
||||
console.log('LDAPCtrl: triggerChangedUsersSync');
|
||||
triggerSync('triggerChangedUsersSync');
|
||||
}
|
||||
|
||||
function triggerSync(action) {
|
||||
UserFederationSync.get({ action: action, realm: $scope.realm.realm, provider: $scope.instance.id }, function() {
|
||||
Notifications.success("Sync of users finished successfully");
|
||||
}, function() {
|
||||
Notifications.error("Error during sync of users");
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -217,6 +217,10 @@ module.factory('UserFederationProviders', function($resource) {
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('UserFederationSync', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/user-federation/sync/:provider');
|
||||
});
|
||||
|
||||
|
||||
module.factory('UserSessionStats', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/users/:user/session-stats', {
|
||||
|
|
|
@ -40,6 +40,34 @@
|
|||
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">Sync settings</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="fullSyncEnabled">Periodic full sync</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="fullSyncEnabled" name="fullSyncEnabled" id="fullSyncEnabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="fullSyncEnabled">
|
||||
<label class="col-sm-2 control-label" for="fullSyncPeriod">Full sync period</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="number" ng-model="instance.fullSyncPeriod" id="fullSyncPeriod" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="changedSyncEnabled">Periodic changed users sync</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="changedSyncEnabled" name="changedSyncEnabled" id="changedSyncEnabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="changedSyncEnabled">
|
||||
<label class="col-sm-2 control-label" for="changedSyncPeriod">Changed users sync period</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="number" ng-model="instance.changedSyncPeriod" id="changedSyncPeriod" />
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageUsers">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
|
@ -49,6 +77,8 @@
|
|||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
<button kc-delete data-ng-click="triggerFullSync()" data-ng-hide="changed">Synchronize all users</button>
|
||||
<button kc-delete data-ng-click="triggerChangedUsersSync()" data-ng-hide="changed">Synchronize changed users</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -133,6 +133,40 @@
|
|||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">Sync settings</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="batchSizeForSync">Batch size</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" ng-model="instance.config.batchSizeForSync" id="batchSizeForSync" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="fullSyncEnabled">Periodic full sync</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="fullSyncEnabled" name="fullSyncEnabled" id="fullSyncEnabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="fullSyncEnabled">
|
||||
<label class="col-sm-2 control-label" for="fullSyncPeriod">Full sync period</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="number" ng-model="instance.fullSyncPeriod" id="fullSyncPeriod" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="changedSyncEnabled">Periodic changed users sync</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="changedSyncEnabled" name="changedSyncEnabled" id="changedSyncEnabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="changedSyncEnabled">
|
||||
<label class="col-sm-2 control-label" for="changedSyncPeriod">Changed users sync period</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="number" ng-model="instance.changedSyncPeriod" id="changedSyncPeriod" />
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageUsers">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
|
@ -142,6 +176,8 @@
|
|||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
<button kc-delete data-ng-click="triggerFullSync()" data-ng-hide="changed">Synchronize all users</button>
|
||||
<button kc-delete data-ng-click="triggerChangedUsersSync()" data-ng-hide="changed">Synchronize changed users</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -122,12 +122,14 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
cache.clear();
|
||||
}
|
||||
runInvalidations();
|
||||
transactionActive = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
setRollbackOnly = true;
|
||||
runInvalidations();
|
||||
transactionActive = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -87,12 +87,14 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
|
|||
cache.clear();
|
||||
}
|
||||
runInvalidations();
|
||||
transactionActive = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
setRollbackOnly = true;
|
||||
runInvalidations();
|
||||
transactionActive = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -144,9 +144,9 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
// Remove all periodic syncs for configured federation providers
|
||||
PeriodicSyncManager periodicSyncManager = new PeriodicSyncManager();
|
||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
||||
periodicSyncManager.removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), fedProvider);
|
||||
usersSyncManager.removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), fedProvider);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
|
@ -218,9 +218,9 @@ public class RealmManager {
|
|||
|
||||
// Refresh periodic sync tasks for configured federationProviders
|
||||
List<UserFederationProviderModel> federationProviders = newRealm.getUserFederationProviders();
|
||||
PeriodicSyncManager periodicSyncManager = new PeriodicSyncManager();
|
||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
||||
periodicSyncManager.startPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, newRealm.getId());
|
||||
usersSyncManager.refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, newRealm.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.services.managers;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
|
@ -16,7 +17,9 @@ import org.keycloak.util.Time;
|
|||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class PeriodicSyncManager {
|
||||
public class UsersSyncManager {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(UsersSyncManager.class);
|
||||
|
||||
/**
|
||||
* Check federationProviderModel of all realms and possibly start periodic sync for them
|
||||
|
@ -24,7 +27,7 @@ public class PeriodicSyncManager {
|
|||
* @param sessionFactory
|
||||
* @param timer
|
||||
*/
|
||||
public void bootstrap(final KeycloakSessionFactory sessionFactory, final TimerProvider timer) {
|
||||
public void bootstrapPeriodic(final KeycloakSessionFactory sessionFactory, final TimerProvider timer) {
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
|
@ -33,27 +36,45 @@ public class PeriodicSyncManager {
|
|||
for (final RealmModel realm : realms) {
|
||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
||||
startPeriodicSyncForProvider(sessionFactory, timer, fedProvider, realm.getId());
|
||||
refreshPeriodicSyncForProvider(sessionFactory, timer, fedProvider, realm.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void startPeriodicSyncForProvider(final KeycloakSessionFactory sessionFactory, TimerProvider timer, final UserFederationProviderModel fedProvider, final String realmId) {
|
||||
public void syncAllUsers(final KeycloakSessionFactory sessionFactory, String realmId, final UserFederationProviderModel fedProvider) {
|
||||
final UserFederationProviderFactory fedProviderFactory = (UserFederationProviderFactory) sessionFactory.getProviderFactory(UserFederationProvider.class, fedProvider.getProviderName());
|
||||
updateLastSyncInterval(sessionFactory, fedProvider, realmId);
|
||||
fedProviderFactory.syncAllUsers(sessionFactory, realmId, fedProvider);
|
||||
}
|
||||
|
||||
public void syncChangedUsers(final KeycloakSessionFactory sessionFactory, String realmId, final UserFederationProviderModel fedProvider) {
|
||||
final UserFederationProviderFactory fedProviderFactory = (UserFederationProviderFactory) sessionFactory.getProviderFactory(UserFederationProvider.class, fedProvider.getProviderName());
|
||||
|
||||
// See when we did last sync.
|
||||
int oldLastSync = fedProvider.getLastSync();
|
||||
updateLastSyncInterval(sessionFactory, fedProvider, realmId);
|
||||
fedProviderFactory.syncChangedUsers(sessionFactory, realmId, fedProvider, Time.toDate(oldLastSync));
|
||||
}
|
||||
|
||||
public void refreshPeriodicSyncForProvider(final KeycloakSessionFactory sessionFactory, TimerProvider timer, final UserFederationProviderModel fedProvider, final String realmId) {
|
||||
if (fedProvider.getFullSyncPeriod() > 0) {
|
||||
// We want periodic full sync for this provider
|
||||
timer.schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
updateLastSyncInterval(sessionFactory, fedProvider, realmId);
|
||||
fedProviderFactory.syncAllUsers(sessionFactory, realmId, fedProvider);
|
||||
try {
|
||||
syncAllUsers(sessionFactory, realmId, fedProvider);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Error occured during full sync of users", t);
|
||||
}
|
||||
}
|
||||
|
||||
}, fedProvider.getFullSyncPeriod() * 1000, fedProvider.getId() + "-FULL");
|
||||
} else {
|
||||
timer.cancelTask(fedProvider.getId() + "-FULL");
|
||||
}
|
||||
|
||||
if (fedProvider.getChangedSyncPeriod() > 0) {
|
||||
|
@ -62,14 +83,17 @@ public class PeriodicSyncManager {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
// See when we did last sync.
|
||||
int oldLastSync = fedProvider.getLastSync();
|
||||
updateLastSyncInterval(sessionFactory, fedProvider, realmId);
|
||||
fedProviderFactory.syncChangedUsers(sessionFactory, realmId, fedProvider, Time.toDate(oldLastSync));
|
||||
try {
|
||||
syncChangedUsers(sessionFactory, realmId, fedProvider);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Error occured during sync of changed users", t);
|
||||
}
|
||||
}
|
||||
|
||||
}, fedProvider.getChangedSyncPeriod() * 1000, fedProvider.getId() + "-CHANGED");
|
||||
|
||||
} else {
|
||||
timer.cancelTask(fedProvider.getId() + "-CHANGED");
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
|
|||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.BruteForceProtector;
|
||||
import org.keycloak.services.managers.PeriodicSyncManager;
|
||||
import org.keycloak.services.managers.UsersSyncManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.resources.admin.AdminRoot;
|
||||
|
@ -149,7 +149,7 @@ public class KeycloakApplication extends Application {
|
|||
TimerProvider timer = sessionFactory.create().getProvider(TimerProvider.class);
|
||||
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredAuditEvents()), interval, "ClearExpiredAuditEvents");
|
||||
timer.schedule(new ScheduledTaskRunner(sessionFactory, new ClearExpiredUserSessions()), interval, "ClearExpiredUserSessions");
|
||||
new PeriodicSyncManager().bootstrap(sessionFactory, timer);
|
||||
new UsersSyncManager().bootstrapPeriodic(sessionFactory, timer);
|
||||
}
|
||||
|
||||
public KeycloakSessionFactory getSessionFactory() {
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.keycloak.representations.adapters.action.SessionStats;
|
|||
import org.keycloak.representations.idm.RealmAuditRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.LDAPConnectionTestManager;
|
||||
import org.keycloak.services.managers.PeriodicSyncManager;
|
||||
import org.keycloak.services.managers.UsersSyncManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
|
@ -165,9 +165,9 @@ public class RealmAdminResource {
|
|||
|
||||
// Refresh periodic sync tasks for configured federationProviders
|
||||
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
||||
PeriodicSyncManager periodicSyncManager = new PeriodicSyncManager();
|
||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
||||
for (final UserFederationProviderModel fedProvider : federationProviders) {
|
||||
periodicSyncManager.startPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, realm.getId());
|
||||
usersSyncManager.refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, realm.getId());
|
||||
}
|
||||
|
||||
return Response.noContent().build();
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
|
|||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
|
||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||
import org.keycloak.services.managers.PeriodicSyncManager;
|
||||
import org.keycloak.services.managers.UsersSyncManager;
|
||||
import org.keycloak.timer.TimerProvider;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
@ -23,6 +23,7 @@ import javax.ws.rs.PUT;
|
|||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
@ -120,7 +121,7 @@ public class UserFederationResource {
|
|||
}
|
||||
UserFederationProviderModel model = realm.addUserFederationProvider(rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
||||
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
||||
new PeriodicSyncManager().startPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
||||
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
||||
|
||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
|
||||
}
|
||||
|
@ -144,7 +145,7 @@ public class UserFederationResource {
|
|||
UserFederationProviderModel model = new UserFederationProviderModel(id, rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
||||
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
||||
realm.updateUserFederationProvider(model);
|
||||
new PeriodicSyncManager().startPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
||||
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +180,7 @@ public class UserFederationResource {
|
|||
auth.requireManage();
|
||||
UserFederationProviderModel model = new UserFederationProviderModel(id, null, null, -1, null, -1, -1, 0);
|
||||
realm.removeUserFederationProvider(model);
|
||||
new PeriodicSyncManager().removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), model);
|
||||
new UsersSyncManager().removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), model);
|
||||
}
|
||||
|
||||
|
||||
|
@ -202,5 +203,32 @@ public class UserFederationResource {
|
|||
return reps;
|
||||
}
|
||||
|
||||
/**
|
||||
* trigger sync of users
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@Path("sync/{id}")
|
||||
@NoCache
|
||||
public Response syncUsers(@PathParam("id") String providerId, @QueryParam("action") String action) {
|
||||
logger.info("triggerSync");
|
||||
auth.requireManage();
|
||||
|
||||
for (UserFederationProviderModel model : realm.getUserFederationProviders()) {
|
||||
if (model.getId().equals(providerId)) {
|
||||
UsersSyncManager syncManager = new UsersSyncManager();
|
||||
if ("triggerFullSync".equals(action)) {
|
||||
syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), model);
|
||||
} else if ("triggerChangedUsersSync".equals(action)) {
|
||||
syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), model);
|
||||
}
|
||||
return Response.noContent().build();
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundException("could not find provider");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.junit.Test;
|
|||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.examples.federation.properties.ClasspathPropertiesFederationFactory;
|
||||
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
||||
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
||||
import org.keycloak.federation.ldap.LDAPUtils;
|
||||
|
@ -23,11 +22,10 @@ import org.keycloak.models.UserFederationProviderFactory;
|
|||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.services.managers.PeriodicSyncManager;
|
||||
import org.keycloak.services.managers.UsersSyncManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.LDAPRule;
|
||||
import org.keycloak.testutils.DummyUserFederationProvider;
|
||||
import org.keycloak.testutils.DummyUserFederationProviderFactory;
|
||||
import org.keycloak.testutils.LDAPEmbeddedServer;
|
||||
import org.keycloak.timer.TimerProvider;
|
||||
|
@ -84,29 +82,43 @@ public class SyncProvidersTest {
|
|||
|
||||
@Test
|
||||
public void testLDAPSync() {
|
||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
||||
|
||||
// wait a bit
|
||||
sleep(1000);
|
||||
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
try {
|
||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||
UserFederationProviderFactory ldapFedFactory = (UserFederationProviderFactory)sessionFactory.getProviderFactory(UserFederationProvider.class, LDAPFederationProviderFactory.PROVIDER_NAME);
|
||||
ldapFedFactory.syncAllUsers(sessionFactory, "test", ldapModel);
|
||||
usersSyncManager.syncAllUsers(sessionFactory, "test", ldapModel);
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, false);
|
||||
}
|
||||
|
||||
// Assert users imported (model test)
|
||||
session = keycloakRule.startSession();
|
||||
try {
|
||||
RealmModel testRealm = session.realms().getRealm("test");
|
||||
UserProvider userProvider = session.userStorage();
|
||||
// Assert users imported
|
||||
assertUserImported(userProvider, testRealm, "user1", "User1FN", "User1LN", "user1@email.org");
|
||||
assertUserImported(userProvider, testRealm, "user2", "User2FN", "User2LN", "user2@email.org");
|
||||
assertUserImported(userProvider, testRealm, "user3", "User3FN", "User3LN", "user3@email.org");
|
||||
assertUserImported(userProvider, testRealm, "user4", "User4FN", "User4LN", "user4@email.org");
|
||||
assertUserImported(userProvider, testRealm, "user5", "User5FN", "User5LN", "user5@email.org");
|
||||
|
||||
// Assert lastSync time updated
|
||||
Assert.assertTrue(ldapModel.getLastSync() > 0);
|
||||
for (UserFederationProviderModel persistentFedModel : testRealm.getUserFederationProviders()) {
|
||||
if (LDAPFederationProviderFactory.PROVIDER_NAME.equals(persistentFedModel.getProviderName())) {
|
||||
Assert.assertTrue(persistentFedModel.getLastSync() > 0);
|
||||
} else {
|
||||
// Dummy provider has still 0
|
||||
Assert.assertEquals(0, persistentFedModel.getLastSync());
|
||||
}
|
||||
}
|
||||
|
||||
// wait a bit
|
||||
sleep(1000);
|
||||
Date beforeLDAPUpdate = new Date();
|
||||
|
||||
// Add user to LDAP and update 'user5' in LDAP
|
||||
PartitionManager partitionManager = FederationProvidersIntegrationTest.getPartitionManager(session, ldapModel);
|
||||
|
@ -119,8 +131,7 @@ public class SyncProvidersTest {
|
|||
|
||||
// Trigger partial sync
|
||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||
UserFederationProviderFactory ldapFedFactory = (UserFederationProviderFactory)sessionFactory.getProviderFactory(UserFederationProvider.class, LDAPFederationProviderFactory.PROVIDER_NAME);
|
||||
ldapFedFactory.syncChangedUsers(sessionFactory, "test", ldapModel, beforeLDAPUpdate);
|
||||
usersSyncManager.syncChangedUsers(sessionFactory, "test", ldapModel);
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, false);
|
||||
}
|
||||
|
@ -147,12 +158,12 @@ public class SyncProvidersTest {
|
|||
int changed = dummyFedFactory.getChangedSyncCounter();
|
||||
|
||||
// Assert that after some period was DummyUserFederationProvider triggered
|
||||
PeriodicSyncManager periodicSyncManager = new PeriodicSyncManager();
|
||||
periodicSyncManager.bootstrap(sessionFactory, session.getProvider(TimerProvider.class));
|
||||
UsersSyncManager usersSyncManager = new UsersSyncManager();
|
||||
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
||||
sleep(1800);
|
||||
|
||||
// Cancel timer
|
||||
periodicSyncManager.removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), dummyModel);
|
||||
usersSyncManager.removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), dummyModel);
|
||||
|
||||
// Assert that DummyUserFederationProviderFactory.syncChangedUsers was invoked
|
||||
int newChanged = dummyFedFactory.getChangedSyncCounter();
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.testsuite.model;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class TransactionsTest {
|
||||
|
||||
@ClassRule
|
||||
public static KeycloakRule kc = new KeycloakRule();
|
||||
|
||||
@Test
|
||||
public void testTransactionActive() {
|
||||
KeycloakSession session = kc.startSession();
|
||||
|
||||
Assert.assertTrue(session.getTransaction().isActive());
|
||||
session.getTransaction().commit();
|
||||
Assert.assertFalse(session.getTransaction().isActive());
|
||||
|
||||
session.getTransaction().begin();
|
||||
Assert.assertTrue(session.getTransaction().isActive());
|
||||
session.getTransaction().rollback();
|
||||
Assert.assertFalse(session.getTransaction().isActive());
|
||||
|
||||
session.close();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue