Commit d686e6f3 authored by michael.simon's avatar michael.simon
Browse files

make NC migration registration more complete

parent 5ba5ba3a
......@@ -67,4 +67,8 @@ public interface RegistryDao extends BaseDao<RegistryEntity, Long> {
List<RegistryEntity> findByServiceAndStatusAndIDPGood(String serviceShortName, RegistryStatus status, Date date,
int limit);
List<RegistryEntity> findByServiceOrderByRecon(ServiceEntity service, int limit);
List<RegistryEntity> findByServiceAndStatusOrderByRecon(ServiceEntity service, RegistryStatus status, int limit);
}
......@@ -83,6 +83,32 @@ public class JpaRegistryDao extends JpaBaseDao<RegistryEntity, Long> implements
return em.createQuery(criteria).getResultList();
}
@Override
public List<RegistryEntity> findByServiceOrderByRecon(ServiceEntity service, int limit) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<RegistryEntity> criteria = builder.createQuery(RegistryEntity.class);
Root<RegistryEntity> root = criteria.from(RegistryEntity.class);
criteria.where(builder.equal(root.get(RegistryEntity_.service), service));
criteria.orderBy(builder.asc(root.get(RegistryEntity_.lastReconcile)));
criteria.select(root);
return em.createQuery(criteria).setMaxResults(limit).getResultList();
}
@Override
public List<RegistryEntity> findByServiceAndStatusOrderByRecon(ServiceEntity service, RegistryStatus status, int limit) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<RegistryEntity> criteria = builder.createQuery(RegistryEntity.class);
Root<RegistryEntity> root = criteria.from(RegistryEntity.class);
criteria.where(builder.and(
builder.equal(root.get("service"), service),
builder.equal(root.get("registryStatus"), status)));
criteria.orderBy(builder.asc(root.get(RegistryEntity_.lastReconcile)));
criteria.select(root);
return em.createQuery(criteria).setMaxResults(limit).getResultList();
}
@SuppressWarnings("unchecked")
@Override
public List<RegistryEntity> findByServiceAndStatus(String serviceShortName, RegistryStatus status, Date date, int limit) {
......
package edu.kit.scc.syncshare.reg;
import java.util.UUID;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -9,46 +16,39 @@ import edu.kit.scc.nextcloud.NextcloudAnswer;
import edu.kit.scc.nextcloud.NextcloudWorker;
import edu.kit.scc.webreg.audit.Auditor;
import edu.kit.scc.webreg.entity.RegistryEntity;
import edu.kit.scc.webreg.entity.RegistryStatus;
import edu.kit.scc.webreg.entity.ScriptEntity;
import edu.kit.scc.webreg.entity.ServiceEntity;
import edu.kit.scc.webreg.entity.UserEntity;
import edu.kit.scc.webreg.entity.audit.AuditStatus;
import edu.kit.scc.webreg.exc.PropertyReaderException;
import edu.kit.scc.webreg.exc.RegisterException;
import edu.kit.scc.webreg.script.ScriptingEnv;
import edu.kit.scc.webreg.service.reg.Infotainment;
import edu.kit.scc.webreg.service.reg.InfotainmentCapable;
import edu.kit.scc.webreg.service.reg.InfotainmentTreeNode;
import edu.kit.scc.webreg.service.reg.RegisterUserWorkflow;
import edu.kit.scc.webreg.service.reg.ScriptingWorkflow;
import edu.kit.scc.webreg.service.reg.ldap.PropertyReader;
public class PfNcMigrationRegisterWorkflow extends PowerFolderRegisterWorkflow
implements RegisterUserWorkflow, InfotainmentCapable {
implements RegisterUserWorkflow, InfotainmentCapable, ScriptingWorkflow {
private static final Logger logger = LoggerFactory.getLogger(PfNcMigrationRegisterWorkflow.class);
protected ScriptingEnv scriptingEnv;
@Override
public void registerUser(UserEntity user, ServiceEntity service,
RegistryEntity registry, Auditor auditor) throws RegisterException {
super.registerUser(user, service, registry, auditor);
PropertyReader prop = PropertyReader.newRegisterPropReader(service);
String idKey = "nextcloud_user_id";
if (prop.readPropOrNull("id_key") != null) {
idKey = prop.readPropOrNull("id_key");
}
String scope = "bwidm.scc.kit.edu";
if (prop.readPropOrNull("id_scope") != null) {
idKey = prop.readPropOrNull("id_scope");
}
updateRegistry(user, service, registry, auditor);
reconciliation(user, service, registry, auditor);
if (! user.getGenericStore().containsKey(idKey)) {
user.getGenericStore().put(idKey, UUID.randomUUID().toString() + "@" + scope);
logger.debug("Generating new {} for user {}: {}", idKey, user.getId(), user.getGenericStore().get(idKey));
}
PropertyReader prop = PropertyReader.newRegisterPropReader(service);
if (! registry.getRegistryValues().containsKey("id")) {
registry.getRegistryValues().put("id", user.getGenericStore().get(idKey));
}
NextcloudWorker worker = new NextcloudWorker(prop);
NextcloudAnswer answer = worker.loadAccount(registry);
......@@ -63,7 +63,83 @@ public class PfNcMigrationRegisterWorkflow extends PowerFolderRegisterWorkflow
throw new RegisterException("Failed to enable account");
}
}
}
}
@Override
public Boolean updateRegistry(UserEntity user, ServiceEntity service,
RegistryEntity registry, Auditor auditor) throws RegisterException {
boolean pfUpdate = super.updateRegistry(user, service, registry, auditor);
PropertyReader prop = PropertyReader.newRegisterPropReader(service);
Map<String, String> reconMap = new HashMap<String, String>();
try {
String scriptName = prop.readProp("script_name");
ScriptEntity scriptEntity = scriptingEnv.getScriptDao().findByName(scriptName);
if (scriptEntity == null)
throw new RegisterException("service not configured properly. script is missing.");
if (scriptEntity.getScriptType().equalsIgnoreCase("javascript")) {
ScriptEngine engine = (new ScriptEngineManager()).getEngineByName(scriptEntity.getScriptEngine());
if (engine == null)
throw new RegisterException("service not configured properly. engine not found: " + scriptEntity.getScriptEngine());
engine.eval(scriptEntity.getScript());
Invocable invocable = (Invocable) engine;
invocable.invokeFunction("updateRegistry", scriptingEnv, reconMap, user, registry, service, auditor, prop, logger);
}
else {
throw new RegisterException("unkown script type: " + scriptEntity.getScriptType());
}
} catch (PropertyReaderException e) {
throw new RegisterException(e);
} catch (ScriptException e) {
throw new RegisterException(e);
} catch (NoSuchMethodException e) {
throw new RegisterException(e);
}
Boolean change = false;
for (Entry<String, String> entry : reconMap.entrySet()) {
if (! registry.getRegistryValues().containsKey(entry.getKey())) {
auditor.logAction("", "UPDATE USER REGISTRY", user.getEppn(), "ADD " +
entry.getKey() + ": " + registry.getRegistryValues().get(entry.getKey()) +
" => " + entry.getValue()
, AuditStatus.SUCCESS);
registry.getRegistryValues().put(entry.getKey(), entry.getValue());
change |= true;
}
else if (! registry.getRegistryValues().get(entry.getKey()).equals(entry.getValue())) {
if (entry.getKey().equals("id")) {
// this should not happen. It means the primary Id for the user has changed.
// Nextcloud saml does not support this
logger.warn("Nextcloud User ID for user {} changes from {} to {}! This will create a new user!",
registry.getRegistryValues().get("id"), entry.getValue());
}
auditor.logAction("", "UPDATE USER REGISTRY", user.getEppn(), "REPLACE " +
entry.getKey() + ": " + registry.getRegistryValues().get(entry.getKey()) +
" => " + entry.getValue()
, AuditStatus.SUCCESS);
registry.getRegistryValues().put(entry.getKey(), entry.getValue());
change |= true;
}
}
/*
* only reconcile registry when it's active. All other will only be given the correct attributes
*/
if (registry.getRegistryStatus().equals(RegistryStatus.ACTIVE))
return (pfUpdate | change);
else
return false;
}
@Override
......@@ -71,26 +147,48 @@ public class PfNcMigrationRegisterWorkflow extends PowerFolderRegisterWorkflow
RegistryEntity registry, Auditor auditor) throws RegisterException {
super.reconciliation(user, service, registry, auditor);
PropertyReader prop = PropertyReader.newRegisterPropReader(service);
String idKey = "nextcloud_user_id";
if (prop.readPropOrNull("id_key") != null) {
idKey = prop.readPropOrNull("id_key");
}
NextcloudWorker worker = new NextcloudWorker(prop);
NextcloudAnswer answer = worker.loadAccount(registry);
int statusCode = answer.getMeta().getStatusCode();
if (statusCode == 404) {
// user not found, needs to be created
logger.info("User {} not found, needs to be created (registry id: {})", user.getId(), registry.getId());
answer = worker.createAccount(registry);
if (answer.getMeta().getStatusCode() != 100) {
throw new RegisterException("Registration failed! " + answer.getMeta().getMessage());
}
String scope = "bwidm.scc.kit.edu";
if (prop.readPropOrNull("id_scope") != null) {
idKey = prop.readPropOrNull("id_scope");
// load the created account
answer = worker.loadAccount(registry);
statusCode = answer.getMeta().getStatusCode();
}
if (! user.getGenericStore().containsKey(idKey)) {
user.getGenericStore().put(idKey, UUID.randomUUID().toString() + "@" + scope);
logger.debug("Generating new {} for user {}: {}", idKey, user.getId(), user.getGenericStore().get(idKey));
if (statusCode != 100) {
// could not load or create account
logger.warn("Status code {} for registry {} (userid {}) is unknown. Message: {}",
new Object[]{ statusCode, registry.getId(), registry.getUser().getId(),
answer.getMeta().getStatus()});
throw new RegisterException("Registration failed! Could not load or create account: " + answer.getMeta().getMessage());
}
logger.debug("Account for registry {} successfully loaded", registry.getId());
if (! registry.getRegistryValues().containsKey("id")) {
registry.getRegistryValues().put("id", user.getGenericStore().get(idKey));
}
worker.updateAccount(registry);
if (registry.getRegistryValues().containsKey("primaryGroup")) {
logger.debug("Creating group {} for registry {}",
registry.getRegistryValues().containsKey("primaryGroup"), registry.getId());
NextcloudAnswer groupAnswer = worker.createGroup(registry.getRegistryValues().get("primaryGroup"));
if (groupAnswer.getMeta().getStatusCode() == 100 || groupAnswer.getMeta().getStatusCode() == 102) {
worker.addUserToGroup(registry, registry.getRegistryValues().get("primaryGroup"));
logger.debug("Adding user {} to group {} for registry {}",
user.getId(), registry.getRegistryValues().get("primaryGroup"), registry.getId());
}
}
}
@Override
......@@ -150,5 +248,9 @@ public class PfNcMigrationRegisterWorkflow extends PowerFolderRegisterWorkflow
}
}
@Override
public void setScriptingEnv(ScriptingEnv env) {
this.scriptingEnv = env;
}
}
/*******************************************************************************
* Copyright (c) 2014 Michael Simon.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Michael Simon - initial
******************************************************************************/
package edu.kit.scc.webreg.job;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.kit.scc.webreg.entity.RegistryEntity;
import edu.kit.scc.webreg.entity.RegistryStatus;
import edu.kit.scc.webreg.entity.ServiceEntity;
import edu.kit.scc.webreg.exc.RegisterException;
import edu.kit.scc.webreg.service.RegistryService;
import edu.kit.scc.webreg.service.ServiceService;
import edu.kit.scc.webreg.service.reg.RegisterUserService;
public class ReconServiceRegistryLimited extends AbstractExecutableJob {
private static final long serialVersionUID = 1L;
@Override
public void execute() {
Logger logger = LoggerFactory.getLogger(ReconServiceRegistryLimited.class);
logger.info("Starting Recon Job");
if (! getJobStore().containsKey("full_recon")) {
logger.warn("ReconServiceRegistry Job is not configured correctly. full_recon Parameter is missing in JobMap");
return;
}
if (! getJobStore().containsKey("service_short_name")) {
logger.warn("ReconServiceRegistry Job is not configured correctly. service_short_name Parameter is missing in JobMap");
return;
}
if (! getJobStore().containsKey("limit")) {
logger.warn("ReconServiceRegistry Job is not configured correctly. full_recon Parameter is missing in JobMap");
return;
}
Boolean fullRecon = Boolean.parseBoolean(getJobStore().get("full_recon"));
String serviceShortName = getJobStore().get("service_short_name");
Integer limit = Integer.parseInt(getJobStore().get("limit"));
Boolean allStatus = false;
if (getJobStore().containsKey("all_status")) {
allStatus = Boolean.parseBoolean(getJobStore().get("all_status"));
}
logger.debug("Recon Job configured for service {}: fullRecon is {}, limit is {}", serviceShortName, fullRecon, limit);
try {
InitialContext ic = new InitialContext();
ServiceService serviceService = (ServiceService) ic.lookup("global/bwreg/bwreg-service/ServiceServiceImpl!edu.kit.scc.webreg.service.ServiceService");
RegistryService registryService = (RegistryService) ic.lookup("global/bwreg/bwreg-service/RegistryServiceImpl!edu.kit.scc.webreg.service.RegistryService");
ServiceEntity service = serviceService.findByShortName(serviceShortName);
if (service == null) {
logger.warn("No service by short name {} found! Stopping Recon", serviceShortName);
return;
}
List<RegistryEntity> registryList;
if (allStatus) {
registryList = registryService.findByServiceOrderByRecon(service, limit);
}
else {
registryList = registryService.findByServiceAndStatusOrderByRecon(service, RegistryStatus.ACTIVE, limit);
}
logger.info("Found {} registries for service {}", registryList.size(), service.getName());
RegisterUserService registerUserService = (RegisterUserService) ic.lookup("global/bwreg/bwreg-service/RegisterUserServiceImpl!edu.kit.scc.webreg.service.reg.RegisterUserService");
for (RegistryEntity registry : registryList) {
logger.info("Recon registry {}", registry.getId());
try {
registerUserService.reconsiliation(registry, fullRecon, "recon-job");
} catch (RegisterException e) {
logger.warn("Could not recon registry {}: {}", registry.getId(), e);
}
}
logger.info("Limited recon done for service {}", service.getName());
} catch (NamingException e) {
logger.warn("Could not Recon Service: {}", e);
}
}
}
......@@ -64,4 +64,8 @@ public interface RegistryService extends BaseService<RegistryEntity, Long> {
List<RegistryEntity> findByServiceAndStatusAndIDPGood(String serviceShortName, RegistryStatus status, Date date,
int limit);
List<RegistryEntity> findByServiceOrderByRecon(ServiceEntity service, int limit);
List<RegistryEntity> findByServiceAndStatusOrderByRecon(ServiceEntity service, RegistryStatus status, int limit);
}
......@@ -64,6 +64,11 @@ public class RegistryServiceImpl extends BaseServiceImpl<RegistryEntity, Long> i
return dao.findByServiceAndStatus(service, status);
}
@Override
public List<RegistryEntity> findByServiceAndStatusOrderByRecon(ServiceEntity service, RegistryStatus status, int limit) {
return dao.findByServiceAndStatusOrderByRecon(service, status, limit);
}
@Override
public List<RegistryEntity> findByServiceAndNotStatus(ServiceEntity service, RegistryStatus... status) {
return dao.findByServiceAndNotStatus(service, status);
......@@ -102,6 +107,11 @@ public class RegistryServiceImpl extends BaseServiceImpl<RegistryEntity, Long> i
return dao.findByService(service);
}
@Override
public List<RegistryEntity> findByServiceOrderByRecon(ServiceEntity service, int limit) {
return dao.findByServiceOrderByRecon(service, limit);
}
@Override
public List<RegistryEntity> findByUserAndStatus(UserEntity user, RegistryStatus... status) {
return dao.findByUserAndStatus(user, status);
......
......@@ -186,10 +186,7 @@
<p:commandButton id="recon3" action="#{showServiceBean.startRecon(true, true, true)}" value="#{messages.full_reconsiliation_with_groups}"
ajax="false"/>
</div>
<div>
<p:commandButton id="recon4" action="#{showServiceBean.startRecon(true, false, false)}" value="#{messages.full_reconsiliation_all_status}"
ajax="false"/>
<div>
<h:link outcome="compare-child-registries.xhtml" value="#{messages.compare_child_registries}">
<f:param name="id" value="#{showServiceBean.entity.id}" />
</h:link>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment