Skip to content
Permalink
Browse files
[AMBARI-25062] Optionally execute the post user creation hook on exis…
…ting users during LDAP sync

* [AMBARI-25062] Optionally execute the post user creation hook on existing users during LDAP sync

* [AMBARI-25062] Optionally execute the post user creation hook on existing users during LDAP sync
  • Loading branch information
rlevas committed Dec 21, 2018
1 parent 7f9d14b commit fa3c6850f2426b01d2fa5e1fb2876cf901fddadb
Show file tree
Hide file tree
Showing 16 changed files with 471 additions and 99 deletions.
@@ -185,6 +185,7 @@
import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator;
import org.apache.ambari.server.security.ldap.LdapBatchDto;
import org.apache.ambari.server.security.ldap.LdapSyncDto;
import org.apache.ambari.server.security.ldap.LdapUserDto;
import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException;
import org.apache.ambari.server.serveraction.kerberos.KerberosOperationException;
import org.apache.ambari.server.stack.ExtensionHelper;
@@ -5141,35 +5142,69 @@ public synchronized LdapBatchDto synchronizeLdapUsersAndGroups(
try {

final LdapBatchDto batchInfo = new LdapBatchDto();
boolean postProcessExistingUsers = false;
boolean postProcessExistingUsersInGroups = false;

if (userRequest != null) {
postProcessExistingUsers = userRequest.getPostProcessExistingUsers();

if(postProcessExistingUsers && !configs.isUserHookEnabled()) {
LOG.warn("Post processing existing users is requested while processing users; however, the user post creation hook is turned off.");
postProcessExistingUsers = false;
}

switch (userRequest.getType()) {
case ALL:
ldapDataPopulator.synchronizeAllLdapUsers(batchInfo);
ldapDataPopulator.synchronizeAllLdapUsers(batchInfo, postProcessExistingUsers);
break;
case EXISTING:
ldapDataPopulator.synchronizeExistingLdapUsers(batchInfo);
ldapDataPopulator.synchronizeExistingLdapUsers(batchInfo, postProcessExistingUsers);
break;
case SPECIFIC:
ldapDataPopulator.synchronizeLdapUsers(userRequest.getPrincipalNames(), batchInfo);
ldapDataPopulator.synchronizeLdapUsers(userRequest.getPrincipalNames(), batchInfo, postProcessExistingUsers);
break;
}
}
if (groupRequest != null) {
postProcessExistingUsersInGroups = groupRequest.getPostProcessExistingUsers();

if(postProcessExistingUsersInGroups && !configs.isUserHookEnabled()) {
LOG.warn("Post processing existing users is requested while processing groups; however, the user post creation hook is turned off.");
postProcessExistingUsersInGroups = false;
}

switch (groupRequest.getType()) {
case ALL:
ldapDataPopulator.synchronizeAllLdapGroups(batchInfo);
ldapDataPopulator.synchronizeAllLdapGroups(batchInfo, postProcessExistingUsersInGroups);
break;
case EXISTING:
ldapDataPopulator.synchronizeExistingLdapGroups(batchInfo);
ldapDataPopulator.synchronizeExistingLdapGroups(batchInfo, postProcessExistingUsersInGroups);
break;
case SPECIFIC:
ldapDataPopulator.synchronizeLdapGroups(groupRequest.getPrincipalNames(), batchInfo);
ldapDataPopulator.synchronizeLdapGroups(groupRequest.getPrincipalNames(), batchInfo, postProcessExistingUsersInGroups);
break;
}
}

users.processLdapSync(batchInfo);

if (postProcessExistingUsers || postProcessExistingUsersInGroups) {
// Execute post user creation hook on ignored users. These users were previously synced with
// Ambari but the post user creation script may not have been run on them due to various
// reasons
Set<LdapUserDto> ignoredUsers = batchInfo.getUsersIgnored();
if(CollectionUtils.isNotEmpty(ignoredUsers)) {
Map<String, Set<String>> userGroupsMap = new HashMap<>();
for (LdapUserDto ignoredUser : ignoredUsers) {
// The set of groups is empty here since the groups are not used in the script and the
// existing usage of the post user creation hook does not supply a set of groups either.
userGroupsMap.put(ignoredUser.getUserName(), Collections.emptySet());
}

users.executeUserHook(userGroupsMap);
}
}

return batchInfo;
} finally {
ldapSyncInProgress = false;
@@ -38,28 +38,35 @@ public class LdapSyncRequest {
*/
private final LdapSyncSpecEntity.SyncType type;

/**
* A Boolean value indicating whether to execute the post user creation hook on previously
* existing users (if the post user creation hook feature has been enabled)
*/
private final boolean postProcessExistingUsers;


// ----- Constructors ------------------------------------------------------

/**
* Construct an LdapSyncRequest.
*
* @param type the request type
* @param principalNames the principal names
* @param type the request type
* @param principalNames the principal names
* @param postProcessExistingUsers true, to process existing users; false, otherwise
*/
public LdapSyncRequest(LdapSyncSpecEntity.SyncType type, Set<String> principalNames) {
this.type = type;
public LdapSyncRequest(LdapSyncSpecEntity.SyncType type, Set<String> principalNames, boolean postProcessExistingUsers) {
this.type = type;
this.principalNames = principalNames == null ? new HashSet<>() : principalNames;
this.postProcessExistingUsers = postProcessExistingUsers;
}

/**
* Construct an LdapSyncRequest.
*
* @param type the request type
*/
public LdapSyncRequest(LdapSyncSpecEntity.SyncType type) {
this.principalNames = new HashSet<>();
this.type = type;
public LdapSyncRequest(LdapSyncSpecEntity.SyncType type, boolean postProcessExistingUsers) {
this(type, null, postProcessExistingUsers);
}


@@ -91,4 +98,14 @@ public Set<String> getPrincipalNames() {
public LdapSyncSpecEntity.SyncType getType() {
return type;
}

/**
* Gets whether to (re)exectue the post user creation hook on previously existing users
* (if the post user creation hook feature has been enabled), on not.
*
* @return true, to process existing users; false, otherwise
*/
public boolean getPostProcessExistingUsers() {
return postProcessExistingUsers;
}
}
@@ -129,6 +129,7 @@ public class LdapSyncEventResourceProvider extends AbstractControllerResourcePro
*/
private static final String PRINCIPAL_TYPE_SPEC_KEY = "principal_type";
private static final String SYNC_TYPE_SPEC_KEY = "sync_type";
private static final String POST_PROCESS_EXISTING_USERS_SPEC_KEY = "post_process_existing_users";
private static final String NAMES_SPEC_KEY = "names";

/**
@@ -318,6 +319,7 @@ private LdapSyncEventEntity toEntity(Map<String, Object> properties) {

LdapSyncSpecEntity.SyncType syncType = null;
LdapSyncSpecEntity.PrincipalType principalType = null;
boolean postProcessExistingUsers = false;

List<String> principalNames = Collections.emptyList();

@@ -332,6 +334,10 @@ private LdapSyncEventEntity toEntity(Map<String, Object> properties) {
} else if (key.equalsIgnoreCase(NAMES_SPEC_KEY)) {
String names = entry.getValue();
principalNames = Arrays.asList(names.split("\\s*,\\s*"));

} else if (key.equalsIgnoreCase(POST_PROCESS_EXISTING_USERS_SPEC_KEY)) {
postProcessExistingUsers = "true".equalsIgnoreCase(entry.getValue());

} else {
throw new IllegalArgumentException("Unknown spec key " + key + ".");
}
@@ -341,7 +347,7 @@ private LdapSyncEventEntity toEntity(Map<String, Object> properties) {
throw new IllegalArgumentException("LDAP event spec must include both sync-type and principal-type.");
}

LdapSyncSpecEntity spec = new LdapSyncSpecEntity(principalType, syncType, principalNames);
LdapSyncSpecEntity spec = new LdapSyncSpecEntity(principalType, syncType, principalNames, postProcessExistingUsers);
specList.add(spec);
}
entity.setSpecs(specList);
@@ -502,13 +508,13 @@ private LdapSyncRequest getLdapRequest(LdapSyncRequest request, LdapSyncSpecEnti

switch (spec.getSyncType()) {
case ALL:
return new LdapSyncRequest(LdapSyncSpecEntity.SyncType.ALL);
return new LdapSyncRequest(LdapSyncSpecEntity.SyncType.ALL, spec.getPostProcessExistingUsers());
case EXISTING:
return new LdapSyncRequest(LdapSyncSpecEntity.SyncType.EXISTING);
return new LdapSyncRequest(LdapSyncSpecEntity.SyncType.EXISTING, spec.getPostProcessExistingUsers());
case SPECIFIC:
Set<String> principalNames = new HashSet<>(spec.getPrincipalNames());
if (request == null ) {
request = new LdapSyncRequest(LdapSyncSpecEntity.SyncType.SPECIFIC, principalNames);
request = new LdapSyncRequest(LdapSyncSpecEntity.SyncType.SPECIFIC, principalNames, spec.getPostProcessExistingUsers());
} else {
request.addPrincipalNames(principalNames);
}
@@ -40,20 +40,27 @@ public class LdapSyncSpecEntity {
*/
private List<String> principalNames;

/**
* A Boolean value indicating whether to (re)exectue the post user creation hook on previously
* existing users (if the post user creation hook feature has been enabled)
*/
private boolean postProcessExistingUsers;

// ----- Constructors ------------------------------------------------------

/**
* Construct an LdapSyncSpecEntity.
*
* @param principalType the principal type
* @param syncType the sync type
* @param principalNames the list of principal names; may not be null
* @param principalType the principal type
* @param syncType the sync type
* @param principalNames the list of principal names; may not be null
* @param postProcessExistingUsers true, to process existing users; false, otherwise
*/
public LdapSyncSpecEntity(PrincipalType principalType, SyncType syncType, List<String> principalNames) {
public LdapSyncSpecEntity(PrincipalType principalType, SyncType syncType, List<String> principalNames, boolean postProcessExistingUsers) {
this.principalType = principalType;
this.syncType = syncType;
this.principalNames = principalNames;
this.postProcessExistingUsers = postProcessExistingUsers;

assert principalNames != null;

@@ -98,6 +105,16 @@ public List<String> getPrincipalNames() {
return principalNames;
}

/**
* Gets whether to execute the post user creation hook on previously existing users
* (if the post user creation hook feature has been enabled), on not.
*
* @return true, to process existing users; false, otherwise
*/
public boolean getPostProcessExistingUsers() {
return postProcessExistingUsers;
}


// ----- enum : PrincipalType ----------------------------------------------

@@ -310,11 +310,28 @@ public synchronized UserEntity createUser(String userName, String localUserName,
userDAO.create(userEntity);

// execute user initialization hook if required ()
hookServiceProvider.get().execute(hookContextFactory.createUserHookContext(validatedUserName));
executeUserHook(validatedUserName);

return userEntity;
}

/**
* Triggers the post user creation hook, if enabled
*
* @param username the username of the user to process
*/
public void executeUserHook(String username) {
hookServiceProvider.get().execute(hookContextFactory.createUserHookContext(username));
}

/**
* Triggers the post user creation hook, if enabled
*
* @param userGroupsMap a map of user names to relevant groups
*/
public void executeUserHook(Map<String, Set<String>> userGroupsMap) {
hookServiceProvider.get().execute(hookContextFactory.createBatchUserHookContext(userGroupsMap));
}

/**
* Removes a user from the Ambari database.

0 comments on commit fa3c685

Please sign in to comment.