Skip to content

Commit

Permalink
[AMBARI-25062] Optionally execute the post user creation hook on exis…
Browse files Browse the repository at this point in the history
…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 authored Dec 21, 2018
1 parent 7f9d14b commit fa3c685
Show file tree
Hide file tree
Showing 16 changed files with 471 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";

/**
Expand Down Expand Up @@ -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();

Expand All @@ -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 + ".");
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 ----------------------------------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit fa3c685

Please sign in to comment.