blob: 1cde5e7efef2ba014593cbff9527cfe9622ec0a7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xasecure.unixusersync.process;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.core.MediaType;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import com.xasecure.unixusersync.config.UserGroupSyncConfig;
import com.xasecure.unixusersync.model.GetXGroupListResponse;
import com.xasecure.unixusersync.model.GetXUserGroupListResponse;
import com.xasecure.unixusersync.model.GetXUserListResponse;
import com.xasecure.unixusersync.model.MUserInfo;
import com.xasecure.unixusersync.model.XGroupInfo;
import com.xasecure.unixusersync.model.XUserGroupInfo;
import com.xasecure.unixusersync.model.XUserInfo;
import com.xasecure.usergroupsync.UserGroupSink;
public class PolicyMgrUserGroupBuilder implements UserGroupSink {
private static final Logger LOG = Logger.getLogger(PolicyMgrUserGroupBuilder.class) ;
public static final String PM_USER_LIST_URI = "/service/xusers/users/" ; // GET
private static final String PM_ADD_USER_URI = "/service/xusers/users/" ; // POST
public static final String PM_GROUP_LIST_URI = "/service/xusers/groups/" ; // GET
private static final String PM_ADD_GROUP_URI = "/service/xusers/groups/" ; // POST
public static final String PM_USER_GROUP_MAP_LIST_URI = "/service/xusers/groupusers/" ; // GET
private static final String PM_ADD_USER_GROUP_LINK_URI = "/service/xusers/groupusers/" ; // POST
private static final String PM_DEL_USER_GROUP_LINK_URI = "/service/xusers/group/${groupName}/user/${userName}" ; // DELETE
private static final String PM_ADD_LOGIN_USER_URI = "/service/users/default" ; // POST
private static String LOCAL_HOSTNAME = "unknown" ;
private String recordsToPullPerCall = "1000" ;
private boolean isMockRun = false ;
private String policyMgrBaseUrl ;
private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance() ;
private List<XGroupInfo> xgroupList = new ArrayList<XGroupInfo>() ;
private List<XUserInfo> xuserList = new ArrayList<XUserInfo>() ;
private List<XUserGroupInfo> xusergroupList = new ArrayList<XUserGroupInfo>() ;
private HashMap<String,XUserInfo> userId2XUserInfoMap = new HashMap<String,XUserInfo>() ;
private HashMap<String,XUserInfo> userName2XUserInfoMap = new HashMap<String,XUserInfo>() ;
private HashMap<String,XGroupInfo> groupName2XGroupInfoMap = new HashMap<String,XGroupInfo>() ;
private String keyStoreFile = null ;
private String keyStoreFilepwd = null;
private String trustStoreFile = null ;
private String trustStoreFilepwd = null ;
private String keyStoreType = null ;
private String trustStoreType = null ;
private HostnameVerifier hv = null ;
private SSLContext sslContext = null ;
static {
try {
LOCAL_HOSTNAME = java.net.InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
LOCAL_HOSTNAME = "unknown" ;
}
}
public static void main(String[] args) throws Throwable {
PolicyMgrUserGroupBuilder ugbuilder = new PolicyMgrUserGroupBuilder() ;
ugbuilder.init() ;
// ugbuilder.print();
// ugbuilder.addMUser("testuser") ;
// ugbuilder.addXUserInfo("testuser") ;
// ugbuilder.addXGroupInfo("testgroup") ;
// XUserInfo u = ugbuilder.addXUserInfo("testuser") ;
// XGroupInfo g = ugbuilder.addXGroupInfo("testgroup") ;
// ugbuilder.addXUserGroupInfo(u, g) ;
}
public void init() throws Throwable {
recordsToPullPerCall = config.getMaxRecordsPerAPICall() ;
policyMgrBaseUrl = config.getPolicyManagerBaseURL() ;
isMockRun = config.isMockRunEnabled() ;
if (isMockRun) {
LOG.setLevel(Level.DEBUG) ;
}
keyStoreFile = config.getSSLKeyStorePath() ;
keyStoreFilepwd = config.getSSLKeyStorePathPassword() ;
trustStoreFile = config.getSSLTrustStorePath() ;
trustStoreFilepwd = config.getSSLTrustStorePathPassword() ;
keyStoreType = KeyStore.getDefaultType() ;
trustStoreType = KeyStore.getDefaultType() ;
buildUserGroupInfo() ;
}
private void buildUserGroupInfo() throws Throwable {
buildGroupList();
buildUserList();
buildUserGroupLinkList() ;
rebuildUserGroupMap() ;
if (LOG.isDebugEnabled()) {
this.print();
}
}
private String getURL(String uri) {
String ret = null ;
ret = policyMgrBaseUrl + (uri.startsWith("/") ? uri : ("/" + uri)) ;
return ret;
}
private void rebuildUserGroupMap() {
for(XUserInfo user : xuserList) {
addUserToList(user);
}
for(XGroupInfo group : xgroupList) {
addGroupToList(group);
}
for(XUserGroupInfo ug : xusergroupList) {
addUserGroupToList(ug);
}
}
private void addUserToList(XUserInfo aUserInfo) {
if (! xuserList.contains(aUserInfo)) {
xuserList.add(aUserInfo) ;
}
String userId = aUserInfo.getId() ;
if (userId != null) {
userId2XUserInfoMap.put(userId, aUserInfo) ;
}
String userName = aUserInfo.getName();
if (userName != null) {
userName2XUserInfoMap.put(userName, aUserInfo) ;
}
}
private void addGroupToList(XGroupInfo aGroupInfo) {
if (! xgroupList.contains(aGroupInfo) ) {
xgroupList.add(aGroupInfo) ;
}
if (aGroupInfo.getName() != null) {
groupName2XGroupInfoMap.put(aGroupInfo.getName(), aGroupInfo) ;
}
}
private void addUserGroupToList(XUserGroupInfo ugInfo) {
String userId = ugInfo.getUserId() ;
if (userId != null) {
XUserInfo user = userId2XUserInfoMap.get(userId) ;
if (user != null) {
List<String> groups = user.getGroups() ;
if (! groups.contains(ugInfo.getGroupName())) {
groups.add(ugInfo.getGroupName()) ;
}
}
}
}
private void delUserGroupFromList(XUserInfo userInfo, XGroupInfo groupInfo) {
List<String> groups = userInfo.getGroups() ;
if (groups.contains(groupInfo.getName())) {
groups.remove(groupInfo.getName()) ;
}
}
private void print() {
LOG.debug("Number of users read [" + xuserList.size() + "]");
for(XUserInfo user : xuserList) {
LOG.debug("USER: " + user.getName()) ;
for(String group : user.getGroups()) {
LOG.debug("\tGROUP: " + group) ;
}
}
}
@Override
public void addOrUpdateUser(String userName, List<String> groups) {
XUserInfo user = userName2XUserInfoMap.get(userName) ;
if (groups == null) {
groups = new ArrayList<String>() ;
}
if (user == null) { // Does not exists
LOG.debug("INFO: addPMAccount(" + userName + ")" ) ;
if (! isMockRun) {
addMUser(userName) ;
}
LOG.debug("INFO: addPMXAUser(" + userName + ")" ) ;
if (! isMockRun) {
user = addXUserInfo(userName) ;
}
for(String g : groups) {
LOG.debug("INFO: addPMXAGroupToUser(" + userName + "," + g + ")" ) ;
}
if (! isMockRun ) {
addXUserGroupInfo(user, groups) ;
}
}
else { // Validate group memberships
List<String> oldGroups = user.getGroups() ;
List<String> addGroups = new ArrayList<String>() ;
List<String> delGroups = new ArrayList<String>() ;
for(String group : groups) {
if (! oldGroups.contains(group)) {
addGroups.add(group) ;
}
}
for(String group : oldGroups) {
if (! groups.contains(group) ) {
delGroups.add(group) ;
}
}
for(String g : addGroups) {
LOG.debug("INFO: addPMXAGroupToUser(" + userName + "," + g + ")" ) ;
}
if (! isMockRun) {
addXUserGroupInfo(user, addGroups) ;
}
for(String g : delGroups) {
LOG.debug("INFO: delPMXAGroupFromUser(" + userName + "," + g + ")" ) ;
}
if (! isMockRun ) {
delXUserGroupInfo(user, delGroups) ;
}
}
}
private void buildGroupList() {
Client c = getClient() ;
int totalCount = 100 ;
int retrievedCount = 0 ;
while (retrievedCount < totalCount) {
WebResource r = c.resource(getURL(PM_GROUP_LIST_URI))
.queryParam("pageSize", recordsToPullPerCall)
.queryParam("startIndex", String.valueOf(retrievedCount)) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
LOG.debug("RESPONSE: [" + response + "]") ;
Gson gson = new GsonBuilder().create() ;
GetXGroupListResponse groupList = gson.fromJson(response, GetXGroupListResponse.class) ;
totalCount = groupList.getTotalCount() ;
if (groupList.getXgroupInfoList() != null) {
xgroupList.addAll(groupList.getXgroupInfoList()) ;
retrievedCount = xgroupList.size() ;
for(XGroupInfo g : groupList.getXgroupInfoList()) {
LOG.debug("GROUP: Id:" + g.getId() + ", Name: " + g.getName() + ", Description: " + g.getDescription()) ;
}
}
}
}
private void buildUserList() {
Client c = getClient() ;
int totalCount = 100 ;
int retrievedCount = 0 ;
while (retrievedCount < totalCount) {
WebResource r = c.resource(getURL(PM_USER_LIST_URI))
.queryParam("pageSize", recordsToPullPerCall)
.queryParam("startIndex", String.valueOf(retrievedCount)) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
Gson gson = new GsonBuilder().create() ;
LOG.debug("RESPONSE: [" + response + "]") ;
GetXUserListResponse userList = gson.fromJson(response, GetXUserListResponse.class) ;
totalCount = userList.getTotalCount() ;
if (userList.getXuserInfoList() != null) {
xuserList.addAll(userList.getXuserInfoList()) ;
retrievedCount = xuserList.size() ;
for(XUserInfo u : userList.getXuserInfoList()) {
LOG.debug("USER: Id:" + u.getId() + ", Name: " + u.getName() + ", Description: " + u.getDescription()) ;
}
}
}
}
private void buildUserGroupLinkList() {
Client c = getClient() ;
int totalCount = 100 ;
int retrievedCount = 0 ;
while (retrievedCount < totalCount) {
WebResource r = c.resource(getURL(PM_USER_GROUP_MAP_LIST_URI))
.queryParam("pageSize", recordsToPullPerCall)
.queryParam("startIndex", String.valueOf(retrievedCount)) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
LOG.debug("RESPONSE: [" + response + "]") ;
Gson gson = new GsonBuilder().create() ;
GetXUserGroupListResponse usergroupList = gson.fromJson(response, GetXUserGroupListResponse.class) ;
totalCount = usergroupList.getTotalCount() ;
if (usergroupList.getXusergroupInfoList() != null) {
xusergroupList.addAll(usergroupList.getXusergroupInfoList()) ;
retrievedCount = xusergroupList.size() ;
for(XUserGroupInfo ug : usergroupList.getXusergroupInfoList()) {
LOG.debug("USER_GROUP: UserId:" + ug.getUserId() + ", Name: " + ug.getGroupName()) ;
}
}
}
}
private XUserInfo addXUserInfo(String aUserName) {
XUserInfo ret = null ;
XUserInfo addUser = new XUserInfo() ;
addUser.setName(aUserName);
addUser.setDescription(aUserName + " - add from Unix box") ;
Client c = getClient() ;
WebResource r = c.resource(getURL(PM_ADD_USER_URI)) ;
Gson gson = new GsonBuilder().create() ;
String jsonString = gson.toJson(addUser) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString) ;
LOG.debug("RESPONSE: [" + response + "]") ;
ret = gson.fromJson(response, XUserInfo.class) ;
if (ret != null) {
addUserToList(ret);
}
return ret ;
}
private XGroupInfo addXGroupInfo(String aGroupName) {
XGroupInfo ret = null ;
XGroupInfo addGroup = new XGroupInfo() ;
addGroup.setName(aGroupName);
addGroup.setDescription(aGroupName + " - add from Unix box") ;
addGroup.setGroupType("1") ;
Client c = getClient() ;
WebResource r = c.resource(getURL(PM_ADD_GROUP_URI)) ;
Gson gson = new GsonBuilder().create() ;
String jsonString = gson.toJson(addGroup) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString) ;
LOG.debug("RESPONSE: [" + response + "]") ;
ret = gson.fromJson(response, XGroupInfo.class) ;
if (ret != null) {
addGroupToList(ret);
}
return ret ;
}
private void addXUserGroupInfo(XUserInfo aUserInfo, List<String> aGroupList) {
for(String groupName : aGroupList) {
XGroupInfo group = groupName2XGroupInfoMap.get(groupName) ;
if (group == null) {
group = addXGroupInfo(groupName) ;
}
addXUserGroupInfo(aUserInfo, group) ;
}
}
private XUserGroupInfo addXUserGroupInfo(XUserInfo aUserInfo, XGroupInfo aGroupInfo) {
XUserGroupInfo ret = null ;
XUserGroupInfo ugInfo = new XUserGroupInfo() ;
ugInfo.setUserId(aUserInfo.getId());
ugInfo.setGroupName(aGroupInfo.getName()) ;
// ugInfo.setParentGroupId("1");
Client c = getClient() ;
WebResource r = c.resource(getURL(PM_ADD_USER_GROUP_LINK_URI)) ;
Gson gson = new GsonBuilder().create() ;
String jsonString = gson.toJson(ugInfo) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString) ;
LOG.debug("RESPONSE: [" + response + "]") ;
ret = gson.fromJson(response, XUserGroupInfo.class) ;
if (ret != null) {
addUserGroupToList(ret);
}
return ret ;
}
private void delXUserGroupInfo(XUserInfo aUserInfo, List<String> aGroupList) {
for(String groupName : aGroupList) {
XGroupInfo group = groupName2XGroupInfoMap.get(groupName) ;
if (group != null) {
delXUserGroupInfo(aUserInfo, group) ;
}
}
}
private void delXUserGroupInfo(XUserInfo aUserInfo, XGroupInfo aGroupInfo) {
Client c = getClient() ;
String uri = PM_DEL_USER_GROUP_LINK_URI.replaceAll(Pattern.quote("${groupName}"), aGroupInfo.getName()).replaceAll(Pattern.quote("${userName}"), aUserInfo.getName()) ;
WebResource r = c.resource(getURL(uri)) ;
ClientResponse response = r.delete(ClientResponse.class) ;
LOG.debug("RESPONSE: [" + response.toString() + "]") ;
if (response.getStatus() == 200) {
delUserGroupFromList(aUserInfo, aGroupInfo) ;
}
}
private MUserInfo addMUser(String aUserName) {
MUserInfo ret = null ;
MUserInfo userInfo = new MUserInfo() ;
userInfo.setLoginId(aUserName);
userInfo.setFirstName(aUserName);
userInfo.setLastName(aUserName);
userInfo.setEmailAddress(aUserName + "@" + LOCAL_HOSTNAME);
Client c = getClient() ;
WebResource r = c.resource(getURL(PM_ADD_LOGIN_USER_URI)) ;
Gson gson = new GsonBuilder().create() ;
String jsonString = gson.toJson(userInfo) ;
String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString) ;
LOG.debug("RESPONSE[" + response + "]") ;
ret = gson.fromJson(response, MUserInfo.class) ;
LOG.debug("MUser Creation successful " + ret);
return ret ;
}
private synchronized Client getClient() {
Client ret = null;
if (policyMgrBaseUrl.startsWith("https://")) {
ClientConfig config = new DefaultClientConfig();
if (sslContext == null) {
try {
KeyManager[] kmList = null;
TrustManager[] tmList = null;
if (keyStoreFile != null && keyStoreFilepwd != null) {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
InputStream in = null ;
try {
in = getFileInputStream(keyStoreFile) ;
if (in == null) {
LOG.error("Unable to obtain keystore from file [" + keyStoreFile + "]");
return ret ;
}
keyStore.load(in, keyStoreFilepwd.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStoreFilepwd.toCharArray());
kmList = keyManagerFactory.getKeyManagers();
}
finally {
if (in != null) {
in.close();
}
}
}
if (trustStoreFile != null && trustStoreFilepwd != null) {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
InputStream in = null ;
try {
in = getFileInputStream(trustStoreFile) ;
if (in == null) {
LOG.error("Unable to obtain keystore from file [" + trustStoreFile + "]");
return ret ;
}
trustStore.load(in, trustStoreFilepwd.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
tmList = trustManagerFactory.getTrustManagers();
}
finally {
if (in != null) {
in.close() ;
}
}
}
sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmList, tmList, new SecureRandom());
hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
return session.getPeerHost().equals(urlHostName);
}
};
}
catch(Throwable t) {
throw new RuntimeException("Unable to create SSLConext for communication to policy manager", t);
}
}
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(hv, sslContext));
ret = Client.create(config);
}
else {
ClientConfig cc = new DefaultClientConfig();
cc.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);
ret = Client.create(cc);
}
return ret ;
}
private InputStream getFileInputStream(String path) throws FileNotFoundException {
InputStream ret = null;
File f = new File(path);
if (f.exists()) {
ret = new FileInputStream(f);
} else {
ret = getClass().getResourceAsStream(path);
if (ret == null) {
if (! path.startsWith("/")) {
ret = getClass().getResourceAsStream("/" + path);
}
}
if (ret == null) {
ret = ClassLoader.getSystemClassLoader().getResourceAsStream(path) ;
if (ret == null) {
if (! path.startsWith("/")) {
ret = ClassLoader.getSystemResourceAsStream("/" + path);
}
}
}
}
return ret;
}
}