package org.rhq.sample.client.java.ldap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.authz.Role;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.ResourceGroupCriteria;
import org.rhq.core.domain.criteria.RoleCriteria;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.client.RemoteClient;
import org.rhq.enterprise.server.auth.SubjectManagerRemote;
import org.rhq.enterprise.server.authz.RoleManagerRemote;
import org.rhq.enterprise.server.resource.ResourceManagerRemote;
import org.rhq.enterprise.server.resource.group.ResourceGroupManagerRemote;
/**
* This sample program utilizes the RHQ Remote API via a Java Client.
*
* The RHQ CLI is the preferred remote client approach for script-based clients. Programmatic Java clients
* can utilize the Remote API via the same mechanism used by the CLI, making use of ClientMain object, as
* done in this sample. This is the recommended mechanism although a remote Java client could als use the
* remote API exposed as WebServices.
*
* @author Jay Shaughnessy
*/
public class SampleLdapClientMain {
// A remote session always starts with a login, define default user/password/server/port
private static String username = "rhqadmin";
private static String password = "rhqadmin";
private static String host = "localhost";
private static int port = 7080;
/**
* This is a standalone remote client but calls to the remote API could be embedded into another application.
*/
public static void main(String[] args) {
if (args.length > 0) {
if ((args.length != 2) && (args.length != 4)) {
System.out
.println("\nUsage: SampleLdapClientMain [ [ username password ] | [username password host port] ]");
System.out.println("\n\nDefault credentials: rhqadmin/rhqadmin");
System.out.println("\n\nDefault host: determined from wsconsume of WSDL");
return;
} else {
username = args[0];
password = args[1];
if (args.length == 4) {
host = args[2];
port = Integer.valueOf(args[3]);
}
}
}
LdapClient ldapClient = null;
try {
ldapClient = new LdapClient();
ldapClient.synchLdapJbasManagers();
} catch (Throwable t) {
System.out.println("Error: " + t);
t.printStackTrace();
} finally {
if (null != ldapClient) {
// clean up the session by logging out from the RHQ server
ldapClient.logout();
}
}
}
/**
* The LdapClient interacts with the RHQ Server to help synchronize a (fake) LDAP server with RHQ.
*/
public static class LdapClient {
// group containing all jbas resources
private static final String JBAS_GROUP = "jbas-resource-group";
// role for jbas managers
private static final String JBAS_MANAGER_ROLE = "jbas-manager-role";
// the users that should be assigned the JBAS_MANAGER_ROLE
private static final List<String> JBAS_MANAGERS = new ArrayList<String>();
// the prmissions that should be assigned the JBAS_MANAGER_ROLE
private static final Set<Permission> JBAS_MANAGER_PERMISSIONS = new HashSet<Permission>();
// jbas AS Server resource type (note, this picks up AS4 and AS5 resources as they share the same type name)
private static final String JBAS_SERVER_NAME = "JBossAS Server";
/* The Remote API offers different remote "managers" roughly broken down by subsystem/function
* Below are the managers needed by this client, there are several others that offer
* interfaces into areas such as operations, alerting, content, etc. See the API.
*/
private ResourceGroupManagerRemote resourceGroupManager;
private ResourceManagerRemote resourceManager;
private RoleManagerRemote roleManager;
private SubjectManagerRemote subjectManager;
/* This represents the RHQ user that is logged in and making the remote calls. This user must
* already exist. For the work being done here the user must also have SECURITY_MANAGER permissions.
*/
private Subject subject;
/* This is the object through which we access the remote API */
private RemoteClient remoteClient;
static {
// add some fake users since we're not actually hooked into an ldap server
JBAS_MANAGERS.add("mgr-1");
JBAS_MANAGERS.add("mgr-2");
// add some permissions since we're not actually hooked into an ldap server
JBAS_MANAGER_PERMISSIONS.addAll(Permission.RESOURCE_ALL);
}
public LdapClient() throws Exception {
this.remoteClient = new RemoteClient(null, host, port);
this.subject = remoteClient.login(username, password);
this.resourceGroupManager = this.remoteClient.getResourceGroupManagerRemote();
this.resourceManager = this.remoteClient.getResourceManagerRemote();
this.roleManager = this.remoteClient.getRoleManagerRemote();
this.subjectManager = this.remoteClient.getSubjectManagerRemote();
}
/*
* This method simulates a synch between an Ldap server that has defined a group of JBAS managers
* and wants to associate them with a role allowing jbas management. Meaning, a role that
* has the proper permissions and is associated with the jbas resources.
*/
private void synchLdapJbasManagers() throws Exception {
// create the jbas manager role if necessary
// use a criteria search with a name filter to look for the role
RoleCriteria roleCriteria = new RoleCriteria();
roleCriteria.setFilterName(JBAS_MANAGER_ROLE);
PageList<Role> jbasManagerRoles = roleManager.findRolesByCriteria(subject, roleCriteria);
Role jbasManagerRole;
if (1 == jbasManagerRoles.size()) {
jbasManagerRole = jbasManagerRoles.get(0);
} else {
// if it doesn't exist, create it
jbasManagerRole = new Role(JBAS_MANAGER_ROLE);
jbasManagerRole = roleManager.createRole(subject, jbasManagerRole);
}
// ensure the proper permissions are granted to the role by using an update
jbasManagerRole.setPermissions(JBAS_MANAGER_PERMISSIONS);
roleManager.updateRole(subject, jbasManagerRole);
// create, populate and associate the jbas group if necessary
ResourceGroupCriteria resourceGroupCriteria = new ResourceGroupCriteria();
resourceGroupCriteria.addFilterName(JBAS_GROUP);
PageList<ResourceGroup> jbasGroups = resourceGroupManager.findResourceGroupsByCriteria(subject,
resourceGroupCriteria);
ResourceGroup jbasGroup;
if (1 == jbasGroups.size()) {
jbasGroup = jbasGroups.get(0);
} else {
jbasGroup = new ResourceGroup(JBAS_GROUP);
jbasGroup = resourceGroupManager.createResourceGroup(subject, jbasGroup);
// Ensure the group is recursive to make all the children available.
// In this case a specific method is available, so a general update call is not needed.
resourceGroupManager.setRecursive(subject, jbasGroup.getId(), true);
}
// Now find all of the JBAS server resources by adding a criteria filter on resource type name
ResourceCriteria resourceCriteria = new ResourceCriteria();
resourceCriteria.addFilterResourceTypeName(JBAS_SERVER_NAME);
PageList<Resource> jbasServers = resourceManager.findResourcesByCriteria(subject, resourceCriteria);
if (!jbasServers.isEmpty()) {
int[] jbasServerIds = new int[jbasServers.size()];
int i = 0;
for (Resource jbasServer : jbasServers) {
jbasServerIds[i++] = jbasServer.getId();
}
// ..and add them to the group which will be associated with the manager role
resourceGroupManager.addResourcesToGroup(subject, jbasGroup.getId(), jbasServerIds);
}
// Now, associate the mixed group of Jbas servers to the manager role
roleManager.addResourceGroupsToRole(subject, jbasManagerRole.getId(), new int[] { jbasGroup.getId() });
// synch managers with the role
// 1. remove obsolete managers
roleCriteria = new RoleCriteria();
roleCriteria.setFilterId(jbasManagerRole.getId());
// add a fetch criteria to the criteria object to get the optionally returned subjects for the role.
roleCriteria.setFetchSubjects(true);
jbasManagerRole = roleManager.findRolesByCriteria(subject, roleCriteria).get(0);
Set<Subject> subjects = jbasManagerRole.getSubjects();
if ((null != subjects) && !subjects.isEmpty()) {
for (Subject subject : subjects) {
if (!JBAS_MANAGERS.contains(subject.getName())) {
roleManager.removeSubjectsFromRole(subject, jbasManagerRole.getId(), new int[] { subject
.getId() });
}
}
}
// 2. add new managers, create subjects for the managers, if necessary
Subject jbasManagerSubject;
for (String jbasManager : JBAS_MANAGERS) {
jbasManagerSubject = subjectManager.getSubjectByName(jbasManager);
// add the required fields for a subject, note that we skip credentials since this is
// simulating ldap
if (null == jbasManagerSubject) {
jbasManagerSubject = new Subject();
jbasManagerSubject.setName(jbasManager);
jbasManagerSubject.setEmailAddress("jbas.manager@sample.com");
jbasManagerSubject.setFactive(true);
jbasManagerSubject.setFsystem(false);
jbasManagerSubject = subjectManager.createSubject(subject, jbasManagerSubject);
}
// Finally, make sure my current set of jbas managers is associated with the manager role.
roleManager.addSubjectsToRole(subject, jbasManagerRole.getId(),
new int[] { jbasManagerSubject.getId() });
}
}
public void logout() {
if ((null != subjectManager) && (null != subject)) {
try {
subjectManager.logout(subject);
} catch (Exception e) {
// just suppress the exception, nothing else we can do
}
}
}
}
}