You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2017/09/20 12:10:51 UTC

[2/2] syncope git commit: Adding GoogleApps support option

Adding GoogleApps support option


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/84a1ae0d
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/84a1ae0d
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/84a1ae0d

Branch: refs/heads/master
Commit: 84a1ae0d8a0bd27bc95aafdc03462951198dc0b4
Parents: f292d86
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Wed Sep 20 14:01:41 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Wed Sep 20 14:10:41 2017 +0200

----------------------------------------------------------------------
 .../GoogleAppsPropagationActions.java           | 159 +++++++++++++++++
 .../java/pushpull/GoogleAppsPullActions.java    | 173 +++++++++++++++++++
 pom.xml                                         |   6 +
 .../concepts/provisioning/propagation.adoc      |   9 +
 .../concepts/provisioning/pull.adoc             |   9 +
 5 files changed, 356 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/84a1ae0d/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
new file mode 100644
index 0000000..1da3578
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
@@ -0,0 +1,159 @@
+/*
+ * 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 org.apache.syncope.core.provisioning.java.propagation;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class is required during setup of an External Resource based on the ConnId
+ * <a href="https://github.com/Tirasa/ConnIdGoogleAppsBundle">GoogleApps connector</a>.
+ *
+ * It manages:
+ * <ol>
+ * <li>the id provided by Google, which will need to be used for all subsequent operations</li>
+ * <li>the e-mail address</li>
+ * </ol>
+ */
+public class GoogleAppsPropagationActions implements PropagationActions {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GoogleAppsPropagationActions.class);
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    protected PlainAttrValueDAO plainAttrValueDAO;
+
+    @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Autowired
+    private AnyUtilsFactory anyUtilsFactory;
+
+    protected String getEmailSchema() {
+        return "email";
+    }
+
+    protected String getGoogleAppsIdSchema() {
+        return "GoogleAppsId";
+    }
+
+    @Transactional
+    @Override
+    public void before(final PropagationTask task, final ConnectorObject beforeObj) {
+        if (task.getOperation() == ResourceOperation.DELETE || task.getOperation() == ResourceOperation.NONE) {
+            return;
+        }
+        if (AnyTypeKind.USER != task.getAnyTypeKind()) {
+            return;
+        }
+
+        Set<Attribute> attrs = new HashSet<>(task.getAttributes());
+
+        // ensure to set __NAME__ value to user's email (e.g. primary e-mail address)
+        User user = userDAO.find(task.getEntityKey());
+        if (user == null) {
+            LOG.error("Could not find user {}, skipping", task.getEntityKey());
+        } else {
+            Name name = AttributeUtil.getNameFromAttributes(attrs);
+            if (name != null) {
+                attrs.remove(name);
+            }
+            attrs.add(new Name(user.getPlainAttr(getEmailSchema()).get().getValuesAsStrings().get(0)));
+        }
+
+        task.setAttributes(attrs);
+    }
+
+    @Transactional
+    @Override
+    public void after(final PropagationTask task, final TaskExec execution, final ConnectorObject afterObj) {
+        if (task.getOperation() == ResourceOperation.DELETE || task.getOperation() == ResourceOperation.NONE) {
+            return;
+        }
+        if (AnyTypeKind.USER != task.getAnyTypeKind()) {
+            return;
+        }
+
+        User user = userDAO.find(task.getEntityKey());
+        if (user == null) {
+            LOG.error("Could not find user {}, skipping", task.getEntityKey());
+        } else {
+            boolean modified = false;
+            AnyUtils anyUtils = anyUtilsFactory.getInstance(user);
+
+            PlainSchema googleAppsId = plainSchemaDAO.find(getGoogleAppsIdSchema());
+            if (googleAppsId == null) {
+                LOG.error("Could not find schema {}, skipping", getGoogleAppsIdSchema());
+            } else {
+                // set back the __UID__ received by Google
+                UPlainAttr attr = user.getPlainAttr(getGoogleAppsIdSchema()).orElse(null);
+                if (attr == null) {
+                    attr = entityFactory.newEntity(UPlainAttr.class);
+                    attr.setSchema(googleAppsId);
+                    attr.setOwner(user);
+                    user.add(attr);
+
+                    try {
+                        attr.add(afterObj.getUid().getUidValue(), anyUtils);
+                        modified = true;
+                    } catch (InvalidPlainAttrValueException e) {
+                        LOG.error("Invalid value for attribute {}: {}",
+                                googleAppsId.getKey(), afterObj.getUid().getUidValue(), e);
+                    }
+                } else {
+                    LOG.debug("User {} has already {} assigned: {}",
+                            user, googleAppsId.getKey(), attr.getValuesAsStrings());
+                }
+            }
+
+            if (modified) {
+                userDAO.save(user);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/84a1ae0d/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/GoogleAppsPullActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/GoogleAppsPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/GoogleAppsPullActions.java
new file mode 100644
index 0000000..7afbada
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/GoogleAppsPullActions.java
@@ -0,0 +1,173 @@
+/*
+ * 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 org.apache.syncope.core.provisioning.java.pushpull;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.patch.StringReplacePatchItem;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.identityconnectors.framework.common.objects.SyncDelta;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class is required during setup of an External Resource based on the ConnId
+ * <a href="https://github.com/Tirasa/ConnIdGoogleAppsBundle">GoogleApps connector</a>.
+ *
+ * It manages:
+ * <ol>
+ * <li>the id provided by Google in response to create, which will need to be used for all subsequent operations</li>
+ * <li>the e-mail address</li>
+ * </ol>
+ */
+public class GoogleAppsPullActions implements PullActions {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GoogleAppsPullActions.class);
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Autowired
+    private AnyUtilsFactory anyUtilsFactory;
+
+    private final Map<String, String> googleAppsIds = new HashMap<>();
+
+    protected String getEmailSchema() {
+        return "email";
+    }
+
+    protected String getGoogleAppsIdSchema() {
+        return "GoogleAppsId";
+    }
+
+    @Override
+    public SyncDelta beforeProvision(
+            final ProvisioningProfile<?, ?> profile,
+            final SyncDelta delta,
+            final EntityTO entity) throws JobExecutionException {
+
+        if (!(entity instanceof UserTO)) {
+            return delta;
+        }
+
+        UserTO userTO = (UserTO) entity;
+        if (userTO.getUsername() == null) {
+            userTO.setUsername(delta.getObject().getName().getNameValue());
+        }
+
+        return delta;
+    }
+
+    @Override
+    public <P extends AnyPatch> SyncDelta beforeUpdate(
+            final ProvisioningProfile<?, ?> profile,
+            final SyncDelta delta,
+            final EntityTO entity,
+            final P anyPatch) throws JobExecutionException {
+
+        if (!(anyPatch instanceof UserPatch)) {
+            return delta;
+        }
+
+        UserPatch userPatch = (UserPatch) anyPatch;
+        if (userPatch.getUsername() == null) {
+            userPatch.setUsername(new StringReplacePatchItem.Builder().
+                    value(delta.getObject().getName().getNameValue()).build());
+        }
+
+        return delta;
+    }
+
+    @Transactional
+    @Override
+    public void after(
+            final ProvisioningProfile<?, ?> profile,
+            final SyncDelta delta,
+            final EntityTO entity,
+            final ProvisioningReport result) throws JobExecutionException {
+
+        if (!(entity instanceof UserTO)) {
+            return;
+        }
+
+        googleAppsIds.put(entity.getKey(), delta.getUid().getUidValue());
+    }
+
+    @Transactional
+    @Override
+    public void afterAll(final ProvisioningProfile<?, ?> profile) throws JobExecutionException {
+        googleAppsIds.entrySet().forEach((entry) -> {
+            User user = userDAO.find(entry.getKey());
+            if (user == null) {
+                LOG.error("Could not find user {}, skipping", entry.getKey());
+            } else {
+                AnyUtils anyUtils = anyUtilsFactory.getInstance(user);
+
+                // 1. stores the __UID__ received by Google
+                PlainSchema googleAppsId = plainSchemaDAO.find(getGoogleAppsIdSchema());
+                if (googleAppsId == null) {
+                    LOG.error("Could not find schema googleAppsId, skipping");
+                } else {
+                    UPlainAttr attr = user.getPlainAttr(getGoogleAppsIdSchema()).orElse(null);
+                    if (attr == null) {
+                        attr = entityFactory.newEntity(UPlainAttr.class);
+                        attr.setSchema(googleAppsId);
+                        attr.setOwner(user);
+                        user.add(attr);
+
+                        try {
+                            attr.add(entry.getValue(), anyUtils);
+                            userDAO.save(user);
+                        } catch (InvalidPlainAttrValueException e) {
+                            LOG.error("Invalid value for attribute {}: {}",
+                                    googleAppsId.getKey(), entry.getValue(), e);
+                        }
+                    } else {
+                        LOG.debug("User {} has already a googleAppsId assigned: {}", user, attr.getValuesAsStrings());
+                    }
+                }
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/84a1ae0d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index fef46f4..cbb292d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -363,6 +363,7 @@ under the License.
     <connid.csvdir.version>0.8.6</connid.csvdir.version>
     <connid.ldap.version>1.5.2</connid.ldap.version>
     <connid.ad.version>1.3.4</connid.ad.version>
+    <connid.googleapps.version>1.4.1-SNAPSHOT</connid.googleapps.version>
 
     <cxf.version>3.2.0</cxf.version>
 
@@ -1719,6 +1720,11 @@ under the License.
                 <artifactId>net.tirasa.connid.bundles.ad</artifactId>
                 <version>${connid.ad.version}</version>
               </artifactItem>
+              <artifactItem>
+                <groupId>net.tirasa.connid.bundles</groupId>
+                <artifactId>net.tirasa.connid.bundles.googleapps</artifactId>
+                <version>${connid.googleapps.version}</version>
+              </artifactItem>
             </artifactItems>
           </configuration>
         </plugin>

http://git-wip-us.apache.org/repos/asf/syncope/blob/84a1ae0d/src/main/asciidoc/reference-guide/concepts/provisioning/propagation.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/concepts/provisioning/propagation.adoc b/src/main/asciidoc/reference-guide/concepts/provisioning/propagation.adoc
index 649e4f8..9c066f1 100644
--- a/src/main/asciidoc/reference-guide/concepts/provisioning/propagation.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/provisioning/propagation.adoc
@@ -110,4 +110,13 @@ endif::[]
 the cipher algorithm associated with the password must match the value of `Password cipher algorithm` for the 
 https://connid.atlassian.net/wiki/display/BASE/Database+Table#DatabaseTable-ConfigurationProperties[DatabaseTable connector bundle^].
 
+| 
+ifeval::["{snapshotOrRelease}" == "release"]
+https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java[GoogleAppsPropagationActions^]
+endif::[]
+ifeval::["{snapshotOrRelease}" == "snapshot"]
+https://github.com/apache/syncope/tree/master/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java[GoogleAppsPropagationActions^]
+endif::[]
+| Required for setup of an External Resource based on the https://connid.atlassian.net/wiki/display/BASE/Google+Apps#GoogleApps-Configuration[ConnId GoogleApps connector bundle^].
+
 |===

http://git-wip-us.apache.org/repos/asf/syncope/blob/84a1ae0d/src/main/asciidoc/reference-guide/concepts/provisioning/pull.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/concepts/provisioning/pull.adoc b/src/main/asciidoc/reference-guide/concepts/provisioning/pull.adoc
index 8358dbb..8f5f9c7 100644
--- a/src/main/asciidoc/reference-guide/concepts/provisioning/pull.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/provisioning/pull.adoc
@@ -134,4 +134,13 @@ endif::[]
 the cipher algorithm associated with the password must match the value of `Password cipher algorithm` for the 
 https://connid.atlassian.net/wiki/display/BASE/Database+Table#DatabaseTable-ConfigurationProperties[DatabaseTable connector bundle^].
 
+|
+ifeval::["{snapshotOrRelease}" == "release"]
+https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/GoogleAppsPullActions.java[GoogleAppsPullActions^]
+endif::[]
+ifeval::["{snapshotOrRelease}" == "snapshot"]
+https://github.com/apache/syncope/tree/master/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/GoogleAppsPullActions.java[GoogleAppsPullActions^]
+endif::[]
+| Required for setup of an External Resource based on the https://connid.atlassian.net/wiki/display/BASE/Google+Apps#GoogleApps-Configuration[ConnId GoogleApps connector bundle^].
+
 |===