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

org.imixs.marty.profile.ProfilePlugin Maven / Gradle / Ivy

/*******************************************************************************
 *  Imixs Workflow 
 *  Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,  
 *  http://www.imixs.com
 *  
 *  This program is free software; you can redistribute it and/or 
 *  modify it under the terms of the GNU General Public License 
 *  as published by the Free Software Foundation; either version 2 
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 *  General Public License for more details.
 *  
 *  You can receive a copy of the GNU General Public
 *  License at http://www.gnu.org/licenses/gpl.html
 *  
 *  Project: 
 *  	http://www.imixs.org
 *  	http://java.net/projects/imixs-workflow
 *  
 *  Contributors:  
 *  	Imixs Software Solutions GmbH - initial API and implementation
 *  	Ralph Soika - Software Developer
 *******************************************************************************/

package org.imixs.marty.profile;

import java.util.Collection;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jakarta.ejb.EJB;
import jakarta.inject.Inject;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.imixs.marty.util.ImageCompactor;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.adminp.AdminPService;
import org.imixs.workflow.engine.plugins.AbstractPlugin;
import org.imixs.workflow.exceptions.InvalidAccessException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;

/**
 * This plug-in supports additional business logic for profile entities. This
 * Plugins is used by the System Workflow only.
 * 

* The plugin verifies the userId and email address for input patterns and * validates for duplicates. The input pattern for the userID can be defined by * the imixs property * *

    *
  • security.userid.input.pattern
  • *
* * The default value is {@code "^[A-Za-z0-9.@\\-\\w]+" } *

* In addition the input mode can be set to LOWERCASE or UPPERCASE. This is * controlled by the imixs property * *

    *
  • security.userid.input.mode
  • *
* The default value is LOWERCASE. * * @author rsoika */ public class ProfilePlugin extends AbstractPlugin { private String userID = null; private static Logger logger = Logger.getLogger(ProfilePlugin.class.getName()); // error codes public static String USERNAME_ALREADY_TAKEN = "USERNAME_ALREADY_TAKEN"; public static String INVALID_USERNAME = "INVALID_USERNAME"; public static String EMAIL_ALREADY_TAKEN = "EMAIL_ALREADY_TAKEN"; public static String INVALID_EMAIL = "INVALID_EMAIL"; public static String NO_PROFILE_SERVICE_FOUND = "NO_PROFILE_SERVICE_FOUND"; // input patterns // public final static String EMAIL_PATTERN = // "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-\\\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[-A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; public final static String DEFAULT_USERID_PATTERN = "^[A-Za-z0-9.@\\-\\w]+"; public final static String DEFAULT_USER_INPUT_MODE = "LOWERCASE"; @EJB AdminPService adminPService; @EJB ImageCompactor imageCompactor; @EJB ProfileService profileService; @Inject @ConfigProperty(name = "security.userid.input.mode", defaultValue = DEFAULT_USER_INPUT_MODE) String userInputMode; @Inject @ConfigProperty(name = "security.userid.input.pattern", defaultValue = DEFAULT_USERID_PATTERN) String userInputPattern; @Inject @ConfigProperty(name = "security.email.input.pattern", defaultValue = EMAIL_PATTERN) String emailInputPattern; @Inject @ConfigProperty(name = "security.email.unique", defaultValue = "true") String sUniqueEmailMode; @Inject @ConfigProperty(name = "profile.image.maxwith", defaultValue = "600") int imageMaxWidth; /** * The Plug-in verifies if the workitem is from the type 'profile'. The plug-in * tests if the usernam or email is unique **/ @Override public ItemCollection run(ItemCollection workItem, ItemCollection documentActivity) throws PluginException { // validate profile.. if ("profile".equals(workItem.getItemValueString("type"))) { validateUserProfile(workItem); // store userID local to discard the cache when close()... userID = workItem.getItemValueString("txtName"); // resize profile image if necessary... try { imageCompactor.resize(workItem, imageMaxWidth); } catch (Exception e) { logger.warning("Unable to resize profile image - " + e.getMessage()); } // load the old user profile ItemCollection oldProfile = this.getWorkflowService().getDocumentService().load(workItem.getUniqueID()); if (oldProfile != null) { // verify if the deputy has changed? String lastDeputy = oldProfile.getItemValueString("namdeputy"); String currentDeputy = workItem.getItemValueString("namdeputy"); if (!currentDeputy.isEmpty() && !currentDeputy.equals(lastDeputy)) { // start an adminP job... createAdminPJob(currentDeputy); } } } return workItem; } /** * Create an AdminP JOB_RENAME_USER. The method expects the source userId and * the target userId. * */ private void createAdminPJob(String targetUserID) { logger.info("namdeputy has changed, staring new ein adminp job: " + userID + "=>" + targetUserID); if (adminPService != null) { ItemCollection adminPJob = new ItemCollection(); adminPJob.replaceItemValue("type", "adminp"); adminPJob.replaceItemValue("typelist", "workitem,childworkitem"); adminPJob.replaceItemValue("namfrom", userID); adminPJob.replaceItemValue("namto ", targetUserID); adminPJob.replaceItemValue("job", AdminPService.JOB_RENAME_USER); adminPService.createJob(adminPJob); } else { logger.warning("Service not injected!"); } } /** * This method discards the cache for the current userID (ProfileService). This * is called only in case a profile was processed and no rollback is called. */ @Override public void close(boolean rollbackTransaction) throws PluginException { // if no rollback we can discard the cache if (!rollbackTransaction && userID != null && !userID.isEmpty()) { // discared cache for this name profileService.discardCache(userID); } super.close(rollbackTransaction); } /** * The method validates the userProfile entity. The txtName property will be * initialized if a new profile is created The txtName property will always be * lower case! * * @param profile * @throws PluginException */ void validateUserProfile(ItemCollection profile) throws PluginException { String sName = profile.getItemValueString("txtName"); String sEmail = profile.getItemValueString("txtEmail"); // is txtname set? if (sName == null || "".equals(sName)) { throw new PluginException(ProfilePlugin.class.getSimpleName(), INVALID_USERNAME, "Missing UserID "); } // Trim names.... if (!sName.equals(sName.trim())) { sName = sName.trim(); profile.replaceItemValue("txtName", sName); } // lower/upper case userid? if ("lowercase".equalsIgnoreCase(userInputMode)) { sName = sName.toLowerCase(); profile.replaceItemValue("txtName", sName); } if ("uppercase".equalsIgnoreCase(userInputMode)) { sName = sName.toUpperCase(); profile.replaceItemValue("txtName", sName); } // validate userid if pattern defined. if (!isValidUserId(sName)) { throw new PluginException(ProfilePlugin.class.getSimpleName(), INVALID_USERNAME, "UserID did not match 'security.userid.input.pattern'=" + userInputPattern, new Object[] { profile.getItemValueString("txtName") }); } // verify email pattern if (!isValidEmailAddress(sEmail)) { throw new PluginException(ProfilePlugin.class.getSimpleName(), INVALID_EMAIL, "Invalid Email Address", new Object[] { profile.getItemValueString("txtEmail") }); } // verify if userid is already taken if (isUserNameTaken(profile)) throw new PluginException(ProfilePlugin.class.getSimpleName(), USERNAME_ALREADY_TAKEN, "Username is already taken - verifiy txtname and txtusername", new Object[] { profile.getItemValueString("txtName") }); // verify if email is already taken if (isEmailTaken(profile)) throw new PluginException(ProfilePlugin.class.getSimpleName(), EMAIL_ALREADY_TAKEN, "Email is already taken - verifiy txtemail", new Object[] { profile.getItemValueString("txtEmail") }); } /** * Validate userID with regular expression provided by the property * 'security.userid.input.pattern' * * @param userid - userID for validation * @return true valid userID, false invalid userID */ public boolean isValidUserId(final String userid) { Pattern pattern; Matcher matcher; if (userInputPattern != null && !userInputPattern.isEmpty()) { pattern = Pattern.compile(userInputPattern); matcher = pattern.matcher(userid); return matcher.matches(); } return true; } /** * Validates a Emailaddress with regular expression * * @param userid - email for validation * @return true valid email, false invalid email */ public boolean isValidEmailAddress(final String email) { Pattern pattern; Matcher matcher; // verify email pattern if (email != null && !email.isEmpty()) { pattern = Pattern.compile(emailInputPattern); matcher = pattern.matcher(email); return matcher.matches(); } return true; } /** * Verifies if the attributes 'txtName' and 'txtUsername' of a user profile are * valid and not yet taken by another profile. The attribute 'txtUsername' is * optional and will be only verified if provided. *

* The txtName (userid) is validated against the property * security.userid.input.mode if defined. * * @param profile - user profile to be validated * @return - true if name isn't still taken by another object and is in a valid * format. */ boolean isUserNameTaken(ItemCollection profile) { String sName = profile.getItemValueString("txtName"); String sUserName = profile.getItemValueString("txtUserName"); String sID = profile.getItemValueString("$uniqueid"); if (!sUserName.equals(sUserName.trim())) { sUserName = sUserName.trim(); profile.replaceItemValue("txtUserName", sUserName); } logger.fine("isUserNameTaken :" + sName); String sQuery; // username provided? if (sUserName != null && !"".equals(sUserName)) { sQuery = "(type:\"profile\" AND (txtname:\"" + sName + "\" OR txtusername:\"" + sUserName + "\")) NOT $uniqueid:\"" + sID + "\""; } else { // query only txtName sQuery = "(type:\"profile\" AND txtname:\"" + sName + "\") NOT $uniqueid:\"" + sID + "\""; } Collection col; try { col = this.getWorkflowService().getDocumentService().find(sQuery, 1, 0); } catch (QueryException e) { throw new InvalidAccessException(InvalidAccessException.INVALID_ID, e.getMessage(), e); } return (col.size() > 0); } /** * Verifies if the txtEmail is still available. * * The validation can be deactivated with the imixs.property * 'security.email.unique=false' * * @param aprofile * @return - true if address isn't still taken by another profile or no email * address is provided. */ boolean isEmailTaken(ItemCollection profile) { // is the unique email mode activated? if (!"true".equalsIgnoreCase(sUniqueEmailMode.trim())) { // validation is deactivated return false; } String sEmail = profile.getItemValueString("txtEmail"); String sID = profile.getItemValueString("$uniqueid"); if (sEmail.isEmpty()) { return false; } // Trim email.... if (!sEmail.equals(sEmail.trim())) { sEmail = sEmail.trim(); profile.replaceItemValue("txtEmail", sEmail); } String sQuery; logger.fine("isEmailTaken :" + sEmail); // username provided? sQuery = "(type:\"profile\" AND txtemail:\"" + sEmail + "\") NOT $uniqueid:\"" + sID + "\""; Collection col; try { col = this.getWorkflowService().getDocumentService().find(sQuery, 1, 0); } catch (QueryException e) { throw new InvalidAccessException(InvalidAccessException.INVALID_ID, e.getMessage(), e); } return (col.size() > 0); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy