All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.internet2.middleware.changelogconsumer.googleapps.GoogleGrouperConnector Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright 2015 Internet2
 * 
 * Licensed 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 edu.internet2.middleware.changelogconsumer.googleapps;

import java.io.IOException;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.api.client.googleapis.GoogleUtils;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.directory.Directory;
import com.google.api.services.directory.model.Group;
import com.google.api.services.directory.model.Member;
import com.google.api.services.directory.model.User;
import com.google.api.services.directory.model.UserName;
import com.google.api.services.groupssettings.Groupssettings;
import com.google.api.services.groupssettings.model.Groups;

import edu.internet2.middleware.changelogconsumer.googleapps.cache.Cache;
import edu.internet2.middleware.changelogconsumer.googleapps.cache.GoogleCacheManager;
import edu.internet2.middleware.changelogconsumer.googleapps.utils.AddressFormatter;
import edu.internet2.middleware.changelogconsumer.googleapps.utils.GoogleAppsSyncProperties;
import edu.internet2.middleware.changelogconsumer.googleapps.utils.RecentlyManipulatedObjectsList;
import edu.internet2.middleware.grouper.GroupFinder;
import edu.internet2.middleware.grouper.GrouperSession;
import edu.internet2.middleware.grouper.Stem;
import edu.internet2.middleware.grouper.StemFinder;
import edu.internet2.middleware.grouper.SubjectFinder;
import edu.internet2.middleware.grouper.attr.AttributeDef;
import edu.internet2.middleware.grouper.attr.AttributeDefName;
import edu.internet2.middleware.grouper.attr.AttributeDefType;
import edu.internet2.middleware.grouper.attr.assign.AttributeAssign;
import edu.internet2.middleware.grouper.attr.finder.AttributeDefFinder;
import edu.internet2.middleware.grouper.attr.finder.AttributeDefNameFinder;
import edu.internet2.middleware.grouper.internal.dao.QueryOptions;
import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
import edu.internet2.middleware.grouper.pit.PITGroup;
import edu.internet2.middleware.grouper.privs.AccessPrivilege;
import edu.internet2.middleware.grouper.util.GrouperUtil;
import edu.internet2.middleware.grouperClient.config.ConfigPropertiesCascadeUtils;
import edu.internet2.middleware.subject.Subject;
import edu.internet2.middleware.subject.provider.SubjectTypeEnum;

/**
 * Contains methods used by both the ChangeLogConsumer and the FullSync classes.
 *
 * @author John Gasper, Unicon
 */
public class GoogleGrouperConnector {
    public static final String SYNC_TO_GOOGLE = "syncToGoogle";
    public static final String GOOGLE_PROVISIONER = "googleProvisioner";
    public static final String ATTRIBUTE_CONFIG_STEM = "etc:attribute";
    public static final String GOOGLE_CONFIG_STEM = ATTRIBUTE_CONFIG_STEM + ":" + GOOGLE_PROVISIONER;
    public static final String SYNC_TO_GOOGLE_NAME = GOOGLE_CONFIG_STEM + ":" + SYNC_TO_GOOGLE;

    private static final Logger LOG = LoggerFactory.getLogger(GoogleGrouperConnector.class);
    /** Global instance of the JSON factory. */
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();

    private Directory directoryClient;
    private Groupssettings groupssettingsClient;

    //The Google Objects hang around a lot longer due to Google API constraints, so they are stored in a static GoogleCacheManager class.
    //Grouper ones are easier to refresh.
    private Cache grouperSubjects;
    private Cache grouperGroups;
    private HashMap syncedObjects;

    private String consumerName;
    private AttributeDefName syncAttribute;
    private GoogleAppsSyncProperties properties;
    private AddressFormatter addressFormatter;
    private RecentlyManipulatedObjectsList recentlyManipulatedObjectsList;

    public GoogleGrouperConnector() {
        grouperSubjects = new Cache();
        grouperGroups = new Cache();
        syncedObjects = new HashMap();
        addressFormatter = new AddressFormatter();
    }

    public void initialize(String consumerName, final GoogleAppsSyncProperties properties) throws GeneralSecurityException, IOException {
        this.consumerName = consumerName;
        this.properties = properties;

        // we check for proxy configuration. if it exists, we set up a proxy. otherwise, just use a default transport
        final HttpTransport httpTransport;
        if (this.properties.getProxyHost() != null && this.properties.getProxyPort() != 0) {
            httpTransport = new NetHttpTransport
                    .Builder()
                    .trustCertificates(GoogleUtils.getCertificateTrustStore())
                    .setProxy(
                            new Proxy(
                                    Proxy.Type.HTTP,
                                    new InetSocketAddress(
                                            properties.getProxyHost(),
                                            properties.getProxyPort()
                                    )
                            )
                    )
                    .build();
        } else {
            httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        }
        
        final GoogleCredential googleDirectoryCredential;
        final GoogleCredential googleGroupssettingsCredential;
        
        if (!StringUtils.isBlank(properties.getServiceAccountPKCS12FilePath())) {
          googleDirectoryCredential = GoogleAppsSdkUtils.getGoogleDirectoryCredential(
                  properties.getServiceAccountEmail(), properties.getServiceAccountPKCS12FilePath(), properties.getServiceImpersonationUser(),
                  httpTransport, JSON_FACTORY, properties.getDirectoryScopes());
  
          googleGroupssettingsCredential = GoogleAppsSdkUtils.getGoogleGroupssettingsCredential(
                  properties.getServiceAccountEmail(), properties.getServiceAccountPKCS12FilePath(), properties.getServiceImpersonationUser(),
                  httpTransport, JSON_FACTORY);
        } else {
          googleDirectoryCredential = GoogleAppsSdkUtils.getGoogleDirectoryCredential(
              properties.getServiceAccountEmail(), properties.getServiceAccountPrivateKey(), properties.getServiceImpersonationUser(),
              httpTransport, JSON_FACTORY, properties.getDirectoryScopes());

          googleGroupssettingsCredential = GoogleAppsSdkUtils.getGoogleGroupssettingsCredential(
              properties.getServiceAccountEmail(), properties.getServiceAccountPrivateKey(), properties.getServiceImpersonationUser(),
              httpTransport, JSON_FACTORY);
        }
          
        directoryClient = new Directory.Builder(httpTransport, JSON_FACTORY, googleDirectoryCredential)
                .setApplicationName("Google Apps Grouper Provisioner")
                .build();

        groupssettingsClient = new Groupssettings.Builder(httpTransport, JSON_FACTORY, googleGroupssettingsCredential)
                .setApplicationName("Google Apps Grouper Provisioner")
                .build();

        addressFormatter.setGroupIdentifierExpression(properties.getGroupIdentifierExpression())
                .setSubjectIdentifierExpression(properties.getSubjectIdentifierExpression())
                .setDomain(properties.getGoogleDomain());

        GoogleCacheManager.googleUsers().setCacheValidity(properties.getGoogleUserCacheValidity());
        GoogleCacheManager.googleGroups().setCacheValidity(properties.getGoogleGroupCacheValidity());

        grouperSubjects.setCacheValidity(5);
        grouperSubjects.seed(1000);

        grouperGroups.setCacheValidity(5);
        grouperGroups.seed(100);

        recentlyManipulatedObjectsList = new RecentlyManipulatedObjectsList(properties.getRecentlyManipulatedQueueSize(), properties.getRecentlyManipulatedQueueDelay());
    }

    /**
     * populates the Google user and group caches.
     */
    public void populateGoogleCache() {
        populateGooUsersCache(directoryClient);
        populateGooGroupsCache(directoryClient);
    }

    public void populateGooUsersCache(Directory directory) {
        LOG.debug("Google Apps Consumer '{}' - Populating the userCache.", consumerName);

        if (GoogleCacheManager.googleUsers().isExpired()) {
            try {
                final List list = GoogleAppsSdkUtils.retrieveAllUsers(directoryClient);
                GoogleCacheManager.googleUsers().seed(list);

            } catch (GoogleJsonResponseException e) {
                LOG.error("Google Apps Consumer '{}' - Something bad happened when populating the userCache: {}", consumerName, e);
            } catch (IOException e) {
                LOG.error("Google Apps Consumer '{}' - Something bad happened when populating the userCache: {}", consumerName, e);
            }
        }
    }

    public void populateGooGroupsCache(Directory directory) {
        LOG.debug("Google Apps Consumer '{}' - Populating the groupCache.", consumerName);

        if (GoogleCacheManager.googleGroups().isExpired()) {
            try {
                final List list = GoogleAppsSdkUtils.retrieveAllGroups(directoryClient);
                GoogleCacheManager.googleGroups().seed(list);

            } catch (GoogleJsonResponseException e) {
                LOG.error("Google Apps Consumer '{}' - Something bad happened when populating the groupCache: {}", consumerName, e);
            } catch (IOException e) {
                LOG.error("Google Apps Consumer '{}' - Something bad happened when populating the groupCache: {}", consumerName, e);
            }
        }
    }

    public Group fetchGooGroup(String groupKey) throws IOException {
        Group group = GoogleCacheManager.googleGroups().get(groupKey);
        if (group == null) {
            group = GoogleAppsSdkUtils.retrieveGroup(directoryClient, groupKey);

            if (group != null) {
                GoogleCacheManager.googleGroups().put(group);
            }
        }

        return group;
    }

    public User fetchGooUser(String userKey) {
        User user = GoogleCacheManager.googleUsers().get(userKey);
        if (user == null) {
            if (!userKey.endsWith(properties.getGoogleDomain())) {
                if (!properties.getAddExternalUsersToGroups()) {
                  return null;
                }
              
                user = new User();
                user.setPrimaryEmail(userKey);
                return user;
            }

            try {
                user = GoogleAppsSdkUtils.retrieveUser(directoryClient, userKey);
            } catch (IOException e) {
                LOG.info("Google Apps Consume '{}' - Error fetching user ({}) from Google: {}; this may not be an actual problem depending upon context.", new Object[]{consumerName, userKey, e.getMessage()});
            }

            if (user != null) {
                GoogleCacheManager.googleUsers().put(user);
            }
        }

        return user;
    }

    public edu.internet2.middleware.grouper.Group fetchGrouperGroup(String groupName) {
        edu.internet2.middleware.grouper.Group group = grouperGroups.get(groupName);
        if (group == null) {
            group = GroupFinder.findByName(GrouperSession.staticGrouperSession(false), groupName, false);

            if (group != null) {
                grouperGroups.put(group);
            }
        }

        return group;
    }

    public Subject fetchGrouperSubject(String sourceId, String subjectId) {
        Subject subject = grouperSubjects.get(sourceId + "__" + subjectId);
        if (subject == null) {
            subject = SubjectFinder.findByIdAndSource(subjectId, sourceId, false);

            if (subject != null) {
                grouperSubjects.put(subject);
            }
        }

        return subject;
    }

    public User createGooUser(Subject subject) throws IOException {
        final String subjectName = subject.getName();
        final String email = addressFormatter.qualifySubjectAddress(subject);

        User newUser = null;
        if (properties.shouldProvisionUsers() && email.endsWith(properties.getGoogleDomain())) {
            LOG.debug("Google Apps Consumer '{}' - Creating organziation Google User {}.", consumerName, email);

            newUser = new User();
            newUser.setPassword(new BigInteger(130, new SecureRandom()).toString(32))
                    .setPrimaryEmail(email)
                    .setIncludeInGlobalAddressList(properties.shouldIncludeUserInGlobalAddressList())
                    .setName(new UserName())
                    .getName().setFullName(subjectName);

            if (properties.useSimpleSubjectNaming()) {
                final String[] subjectNameSplit = subjectName.split(" ");
                newUser.getName().setFamilyName(subjectNameSplit[subjectNameSplit.length - 1])
                        .setGivenName(subjectNameSplit[0]);

            } else {
                newUser.getName().setFamilyName(subject.getAttributeValue(properties.getSubjectSurnameField()))
                        .setGivenName(subject.getAttributeValue(properties.getSubjectGivenNameField()));
            }

            newUser = GoogleAppsSdkUtils.addUser(directoryClient, newUser);
            GoogleCacheManager.googleUsers().put(newUser);
        } else if (properties.getAddExternalUsersToGroups()) {
            LOG.debug("Google Apps Consumer '{}' - Creating a working non-Google user {}.", consumerName, email);

            newUser = new User();
            newUser.setPrimaryEmail(email);
        }

        return newUser;
    }

    public void createGooMember(Group group, User user, String role) throws IOException {
        if (StringUtils.isEmpty(role)) {
            LOG.debug("skipping {}; no role assigned", user.getPrimaryEmail());
            return;
        }

        final Member gMember = new Member();
        gMember.setEmail(user.getPrimaryEmail())
                .setRole(role);

        recentlyManipulatedObjectsList.delayIfNeeded(gMember.getEmail());
        GoogleAppsSdkUtils.addGroupMember(directoryClient, group.getEmail(), gMember);
        recentlyManipulatedObjectsList.add(gMember.getEmail());
    }

    public void createGooGroupIfNecessary(edu.internet2.middleware.grouper.Group grouperGroup) throws IOException {
        final String groupKey = addressFormatter.qualifyGroupAddress(grouperGroup.getName(), grouperGroup.getId());

        Group googleGroup = fetchGooGroup(groupKey);
        recentlyManipulatedObjectsList.delayIfNeeded(groupKey);

        if (googleGroup == null) {
            LOG.debug("Google Apps Consumer '{}' - Creating full group {}.", consumerName, groupKey);

            googleGroup = new Group();
            googleGroup.setName(grouperGroup.getDisplayExtension())
                    .setEmail(groupKey)
                    .setDescription(grouperGroup.getDescription());


            GoogleCacheManager.googleGroups().put(GoogleAppsSdkUtils.addGroup(directoryClient, googleGroup));
            recentlyManipulatedObjectsList.add(groupKey);

            recentlyManipulatedObjectsList.delayIfNeeded(groupKey);

            if (properties.useGroupSettings()) {
                LOG.debug("Google Apps Consumer '{}' - Setting Groupsettings for {}.", consumerName, groupKey);

                final Groups groupSettings = GoogleAppsSdkUtils.retrieveGroupSettings(groupssettingsClient, groupKey);
                final Groups defaultGroupSettings = properties.getDefaultGroupSettings();
                groupSettings.setWhoCanJoin(defaultGroupSettings.getWhoCanJoin())
                        .setWhoCanViewMembership(defaultGroupSettings.getWhoCanViewMembership())
                        .setWhoCanViewGroup(defaultGroupSettings.getWhoCanViewGroup())
                        .setWhoCanInvite(defaultGroupSettings.getWhoCanInvite())
                        .setWhoCanAdd(defaultGroupSettings.getWhoCanAdd())
                        .setAllowExternalMembers(defaultGroupSettings.getAllowExternalMembers())
                        .setWhoCanPostMessage(defaultGroupSettings.getWhoCanPostMessage())
                        .setWhoCanModerateMembers(defaultGroupSettings.getWhoCanModerateMembers())
                        .setAllowWebPosting(defaultGroupSettings.getAllowWebPosting())
                        .setPrimaryLanguage(defaultGroupSettings.getPrimaryLanguage())
                        .setMaxMessageBytes(defaultGroupSettings.getMaxMessageBytes())
                        .setIsArchived(defaultGroupSettings.getIsArchived())
                        .setMessageModerationLevel(defaultGroupSettings.getMessageModerationLevel())
                        .setSpamModerationLevel(defaultGroupSettings.getSpamModerationLevel())
                        .setReplyTo(defaultGroupSettings.getReplyTo())
                        .setCustomReplyTo(defaultGroupSettings.getCustomReplyTo())
                        .setIncludeCustomFooter(defaultGroupSettings.getIncludeCustomFooter())
                        .setCustomFooterText(defaultGroupSettings.getCustomFooterText())
                        .setSendMessageDenyNotification(defaultGroupSettings.getSendMessageDenyNotification())
                        .setDefaultMessageDenyNotificationText(defaultGroupSettings.getDefaultMessageDenyNotificationText())
                        .setShowInGroupDirectory(defaultGroupSettings.getShowInGroupDirectory())
                        .setAllowGoogleCommunication(defaultGroupSettings.getAllowGoogleCommunication())
                        .setMembersCanPostAsTheGroup(defaultGroupSettings.getMembersCanPostAsTheGroup())
                        .setMessageDisplayFont(defaultGroupSettings.getMessageDisplayFont())
                        .setIncludeInGlobalAddressList(defaultGroupSettings.getIncludeInGlobalAddressList())
                        .setWhoCanLeaveGroup(defaultGroupSettings.getWhoCanLeaveGroup())
                        .setWhoCanContactOwner(defaultGroupSettings.getWhoCanContactOwner());
                GoogleAppsSdkUtils.updateGroupSettings(groupssettingsClient, groupKey, groupSettings);
                recentlyManipulatedObjectsList.add(groupKey);
            }

        } else {
          unarchiveGooGroupIfNecessary(googleGroup);
        }

        Set members = grouperGroup.getMembers();
        members.addAll(grouperGroup.getMembers(AccessPrivilege.ADMIN.getField()));
        members.addAll(grouperGroup.getMembers(AccessPrivilege.UPDATE.getField()));
        for (edu.internet2.middleware.grouper.Member member : members) {
            LOG.debug("Google Apps Consumer '{}' - Adding all of the members for {}.", consumerName, groupKey);

            if (member.getSubjectType() == SubjectTypeEnum.PERSON) {
                Subject subject = fetchGrouperSubject(member.getSubjectSourceId(), member.getSubjectId());
                if (subject == null) {
                    continue;
                }
                String userKey = addressFormatter.qualifySubjectAddress(subject);
                User user = fetchGooUser(userKey);

                if (user == null) {
                    user = createGooUser(subject);
                }

                if (user != null) {
                    createGooMember(googleGroup, user, determineRole(member, grouperGroup));
                }
            }
        }
    }

    public String determineRole(edu.internet2.middleware.grouper.Member member, edu.internet2.middleware.grouper.Group group) {
        if (properties.getWhoCanManage().equalsIgnoreCase("SCRIPTED")) {
            final HashMap variableMap = new HashMap();
            variableMap.put("group", group);
            variableMap.put("member", member);

            String role = ConfigPropertiesCascadeUtils.substituteExpressionLanguage(
                    properties.getWhoCanManageJexl(),
                    variableMap, true, false, true, false);

            LOG.debug("Google Apps Consumer '{}' - Scripted role initially calculated the role of '{}' for {} in {}.", new Object[] {consumerName, role, member.getSubjectId(), group.getName()});

            role = StringUtils.isNotBlank(role) ? role.trim() : "MEMBER";

            LOG.debug("Google Apps Consumer '{}' - Final scripted role calculated the role of '{}' for {} in {}.", new Object[] {consumerName, role, member.getSubjectId(), group.getName()});

            return role;

        } else if ((properties.getWhoCanManage().equalsIgnoreCase("BOTH") && member.canUpdate(group))
                || (properties.getWhoCanManage().equalsIgnoreCase("ADMIN") && member.canAdmin(group))
                || (properties.getWhoCanManage().equalsIgnoreCase("UPDATE") && member.canUpdate(group) && !member.canAdmin(group))
                ) {

            LOG.debug("Google Apps Consumer '{}' - Role set to '{}' for {} in {}.", new Object[] {consumerName, "MANAGER", member.getSubjectId(), group.getName()});
            return "MANAGER";

        } else if (member.isMember(group)) {
            LOG.debug("Google Apps Consumer '{}' - Role set to '{}' for {} in {}.", new Object[] {consumerName, "MEMBER", member.getSubjectId(), group.getName()});
            return "MEMBER";
        }

        LOG.debug("Google Apps Consumer '{}' - No role calculated}.", consumerName);
        return null;
    }
    
    public void unarchiveGooGroupIfNecessary(Group group) throws IOException {
        if (!properties.useGroupSettings()) {
            LOG.debug("Google Apps Consumer '{}' - useGroupSetting is false; skipping unarchive for {}.", consumerName, group.getEmail());
            return;
        }

        String groupKey = group.getEmail();
        final Groups defaultGroupSettings = properties.getDefaultGroupSettings();

        recentlyManipulatedObjectsList.delayIfNeeded(groupKey);
        Groups groupssettings = GoogleAppsSdkUtils.retrieveGroupSettings(groupssettingsClient, groupKey);

        if (groupssettings.getArchiveOnly().equalsIgnoreCase("true")) {
            LOG.debug("Google Apps Consumer '{}' - ArchiveOnly=true, setting to false for {}.", consumerName, groupKey);
            groupssettings.setArchiveOnly("false");
            groupssettings.setWhoCanPostMessage(defaultGroupSettings.getWhoCanPostMessage());

            GoogleAppsSdkUtils.updateGroupSettings(groupssettingsClient, groupKey, groupssettings);
            recentlyManipulatedObjectsList.add(groupKey);
        }
    }

    public void deleteGooGroup(edu.internet2.middleware.grouper.Group group) throws IOException {
        deleteGooGroupByName(group.getName(), group.getId());
    }

    public void deleteGooGroup(PITGroup group) throws IOException {
        deleteGooGroupByName(group.getName(), group.getSourceId());
    }
    
    public void deleteGooGroupByName(String groupName) throws IOException {
      deleteGooGroupByName(groupName, null);
    }

    public void deleteGooGroupByName(String groupName, String groupId) throws IOException {
        final String groupKey = addressFormatter.qualifyGroupAddress(groupName, groupId);
        deleteGooGroupByEmail(groupKey);

        grouperGroups.remove(groupName);
        syncedObjects.remove(groupName);
    }

    public void deleteGooGroupByEmail(String groupKey) throws IOException {
        if (properties.getHandleDeletedGroup().equalsIgnoreCase("archive")) {
            LOG.debug("Google Apps Consumer '{}' - Archiving group {}.", consumerName, groupKey);
            recentlyManipulatedObjectsList.delayIfNeeded(groupKey);

            Groups gs = GoogleAppsSdkUtils.retrieveGroupSettings(groupssettingsClient, groupKey);
            gs.setArchiveOnly("true");
            gs.setWhoCanPostMessage("NONE_CAN_POST");
            GoogleAppsSdkUtils.updateGroupSettings(groupssettingsClient, groupKey, gs);

            recentlyManipulatedObjectsList.add(groupKey);

        } else if (properties.getHandleDeletedGroup().equalsIgnoreCase("delete")) {
            LOG.debug("Google Apps Consumer '{}' - Deleting group {}.", consumerName, groupKey);
            recentlyManipulatedObjectsList.delayIfNeeded(groupKey);

            GoogleAppsSdkUtils.removeGroup(directoryClient, groupKey);
            GoogleCacheManager.googleGroups().remove(groupKey);

            recentlyManipulatedObjectsList.delayIfNeeded(groupKey);
        }
        //else "ignore" (we do nothing)

    }


    /**
     * Finds the AttributeDefName specific to this GoogleApps ChangeLog Consumer instance.
     * @return The AttributeDefName for this GoogleApps ChangeLog Consumer
     */
    public AttributeDefName getGoogleSyncAttribute() {
        LOG.debug("Google Apps Consumer '{}' - looking for attribute: {}", consumerName, SYNC_TO_GOOGLE_NAME + consumerName);

        if (syncAttribute != null) {
            return syncAttribute;
        }

        AttributeDefName attrDefName = AttributeDefNameFinder.findByName(SYNC_TO_GOOGLE_NAME + consumerName, false);

        if (attrDefName == null) {
            Stem googleStem = StemFinder.findByName(GrouperSession.staticGrouperSession(), GOOGLE_CONFIG_STEM, false);

            if (googleStem == null) {
                LOG.info("Google Apps Consumer '{}' - {} stem not found, creating it now", consumerName, GOOGLE_CONFIG_STEM);
                final Stem etcAttributeStem = StemFinder.findByName(GrouperSession.staticGrouperSession(), ATTRIBUTE_CONFIG_STEM, false);
                googleStem = etcAttributeStem.addChildStem(GOOGLE_PROVISIONER, GOOGLE_PROVISIONER);
            }

            AttributeDef syncAttrDef = AttributeDefFinder.findByName(SYNC_TO_GOOGLE_NAME + "Def", false);
            if (syncAttrDef == null) {
                LOG.info("Google Apps Consumer '{}' - {} AttributeDef not found, creating it now", consumerName, SYNC_TO_GOOGLE + "Def");
                syncAttrDef = googleStem.addChildAttributeDef(SYNC_TO_GOOGLE + "Def", AttributeDefType.attr);
                syncAttrDef.setAssignToGroup(true);
                syncAttrDef.setAssignToStem(true);
                syncAttrDef.setMultiAssignable(true);
                syncAttrDef.store();
            }

            LOG.info("Google Apps Consumer '{}' - {} attribute not found, creating it now", consumerName, SYNC_TO_GOOGLE_NAME + consumerName);
            attrDefName = googleStem.addChildAttributeDefName(syncAttrDef, SYNC_TO_GOOGLE + consumerName, SYNC_TO_GOOGLE + consumerName);
        }

        syncAttribute = attrDefName;

        return attrDefName;
    }

    public boolean shouldSyncGroup(edu.internet2.middleware.grouper.Group group) {
        boolean result;

        if (group == null) {
            return false;
        }

        final String groupName = group.getName();

        if (syncedObjects.containsKey(groupName)) {
            result = syncedObjects.get(groupName).equalsIgnoreCase("yes");

        } else {
            result = group.getAttributeDelegate().retrieveAssignments(syncAttribute).size() > 0 || shouldSyncStem(group.getParentStem());
            syncedObjects.put(groupName, result ? "yes" : "no");
        }

        return result;
    }

    public boolean shouldSyncStem(Stem stem) {
        boolean result;

        final String stemName = stem.getName();

        if (syncedObjects.containsKey(stemName)) {
            result = syncedObjects.get(stemName).equalsIgnoreCase("yes");

        } else {
            result = stem.getAttributeDelegate().retrieveAssignments(syncAttribute).size() > 0 || !stem.isRootStem() && shouldSyncStem(stem.getParentStem());

            syncedObjects.put(stemName, result ? "yes" : "no");
        }

        return result;
    }

    public boolean shouldSyncStem(String stemName) {
        Stem stem = StemFinder.findByName(GrouperSession.staticGrouperSession(), stemName, false);

        return shouldSyncStem(stem);
    }

    public void cacheSyncedGroupsAndStems() {
        cacheSyncedGroupsAndStems(false);
    }
    public void cacheSyncedGroupsAndStems(boolean fullyPopulate) {
        /* Future: API 2.3.0 has support for getting a list of stems and groups using the Finder objects. */

        final ArrayList ids = new ArrayList();

        //First the users
        Set attributeAssigns = GrouperDAOFactory.getFactory()
                .getAttributeAssign().findStemAttributeAssignments(null, null, GrouperUtil.toSet(syncAttribute.getId()), null, null, true, false);

        for (AttributeAssign attributeAssign : attributeAssigns) {
            ids.add(attributeAssign.getOwnerStemId());
        }
        final Set stems = StemFinder.findByUuids(GrouperSession.staticGrouperSession(), ids, new QueryOptions());
        for (Stem stem : stems) {
            syncedObjects.put(stem.getName(), "yes");

            if (fullyPopulate) {
                for (edu.internet2.middleware.grouper.Group group : stem.getChildGroups(Stem.Scope.SUB)) {
                    syncedObjects.put(group.getName(), "yes");
                }
            }
        }

        //Now for the Groups
        attributeAssigns = GrouperDAOFactory.getFactory()
                .getAttributeAssign().findGroupAttributeAssignments(null, null, GrouperUtil.toSet(syncAttribute.getId()), null, null, true, false);

        for (AttributeAssign attributeAssign : attributeAssigns) {
            final edu.internet2.middleware.grouper.Group group = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), attributeAssign.getOwnerGroupId(), false);
            syncedObjects.put(group.getName(), "yes");
        }
    }

    public void removeGooMembership(String groupName, Subject subject) throws IOException {
      removeGooMembership(groupName, null, subject);
    }

    public void removeGooMembership(String groupName, String groupId, Subject subject) throws IOException {
        final String groupKey = addressFormatter.qualifyGroupAddress(groupName, groupId);
        final String userKey = addressFormatter.qualifySubjectAddress(subject);

        recentlyManipulatedObjectsList.delayIfNeeded(userKey);
        GoogleAppsSdkUtils.removeGroupMember(directoryClient, groupKey, userKey);
        LOG.debug("Google Apps Consumer '{}' - Removed {} from group {}.", new Object[] {consumerName, userKey, groupKey});
        recentlyManipulatedObjectsList.add(userKey);

        if (properties.shouldDeprovisionUsers()) {
            //FUTURE: check if the user has other memberships and if not, initiate the removal here.
        }
    }

    public void removeGooMembership(String groupKey, String subjectEmail) throws IOException {
      recentlyManipulatedObjectsList.delayIfNeeded(subjectEmail);
      GoogleAppsSdkUtils.removeGroupMember(directoryClient, groupKey, subjectEmail);
        LOG.debug("Google Apps Consumer '{}' - Removed {} from group {}.", new Object[] {consumerName, subjectEmail, groupKey});
        recentlyManipulatedObjectsList.add(subjectEmail);

      if (properties.shouldDeprovisionUsers()) {
          //FUTURE: check if the user has other memberships and if not, initiate the removal here.
      }

    }
    
    public Group updateGooGroup(String groupKey, Group group) throws IOException {
        recentlyManipulatedObjectsList.delayIfNeeded(groupKey);
        LOG.debug("Google Apps Consumer '{}' - update Google Group settings {}.", consumerName, groupKey);
        final Group gooGroup = GoogleAppsSdkUtils.updateGroup(directoryClient, groupKey, group);
        recentlyManipulatedObjectsList.add(groupKey);

        return gooGroup;
    }

    public List getGooMembership(String groupKey) throws IOException {
        LOG.debug("Google Apps Consumer '{}' - Getting Google group members {}.", consumerName, groupKey);
        return GoogleAppsSdkUtils.retrieveGroupMembers(directoryClient, groupKey);
    }

    public AddressFormatter getAddressFormatter() {
        return addressFormatter;
    }

    public HashMap getSyncedGroupsAndStems() {
        return syncedObjects;
    }

    public void createGooMember(edu.internet2.middleware.grouper.Group group, Subject subject, String role) throws IOException {
        User user = fetchGooUser(addressFormatter.qualifySubjectAddress(subject));

        if (user == null) {
            user = createGooUser(subject);
            
            if (user != null) {
              LOG.debug("Google Apps Consumer '{}' - Created user {}", consumerName, user);
            }
        }

        Group gooGroup = fetchGooGroup(addressFormatter.qualifyGroupAddress(group.getName(), group.getId()));
        if (user != null && gooGroup != null && StringUtils.isEmpty(role)) {
            LOG.debug("Google Apps Consumer '{}' - Create user {} in {} as {}.", new Object[] {consumerName, user, gooGroup.getId(), role});
            createGooMember(gooGroup, user, role);
        }
    }

    public void updateGooMember(edu.internet2.middleware.grouper.Group group, Subject subject, String role) throws IOException {
        User user = fetchGooUser(addressFormatter.qualifySubjectAddress(subject));

        if (user == null) {
            user = createGooUser(subject);
            if (user == null) {
                LOG.debug("Google Apps Consumer '{}' - No user found, exiting: {}", consumerName, subject.getId());

                return;
            }
        }

        Group gooGroup = fetchGooGroup(addressFormatter.qualifyGroupAddress(group.getName(), group.getId()));
        if (gooGroup == null) {
            LOG.debug("Google Apps Consumer '{}' - No group found, existing: {}", consumerName, group.getName());

            return;
        }

        recentlyManipulatedObjectsList.delayIfNeeded(gooGroup.getEmail());
        Member member = GoogleAppsSdkUtils.retrieveGroupMember(directoryClient, gooGroup.getEmail(), user.getPrimaryEmail());

        if (member == null) {
            if (StringUtils.isNotEmpty(role)){
                LOG.debug("Google Apps Consumer '{}' - Need to add user {} in {} as {}.", new Object[] {consumerName, user.getPrimaryEmail(), gooGroup.getEmail(), role});

                createGooMember(gooGroup, user, role);
            }
            return;
        }

        if (!member.getRole().equalsIgnoreCase(role)) {
            LOG.debug("Google Apps Consumer '{}' - Need to update user role {} from {} to {}.", new Object[] {consumerName, user.getPrimaryEmail(), member.getRole(), role});

            if (StringUtils.isEmpty(role)) {
                LOG.debug("Google Apps Consumer '{}' - Remove role.", consumerName, user);
                GoogleAppsSdkUtils.removeGroupMember(directoryClient, gooGroup.getEmail(), user.getPrimaryEmail());

            } else {
                member.setRole(role);
                LOG.debug("Google Apps Consumer '{}' - Update role {} for {} in {}.", new Object[] {consumerName, role, user.getPrimaryEmail(), gooGroup.getEmail()});
                GoogleAppsSdkUtils.updateGroupMember(directoryClient, gooGroup.getEmail(), user.getPrimaryEmail(), member);
                recentlyManipulatedObjectsList.add(user.getPrimaryEmail());
            }
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy