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

io.imunity.otp.OTPCredentialDefinitionEditor Maven / Gradle / Ivy

/*
 * Copyright (c) 2020 Bixbit - Krzysztof Benedyczak. All rights reserved.
 * See LICENCE.txt file for licensing information.
 */

package io.imunity.otp;

import static com.google.common.base.Strings.isNullOrEmpty;
import static io.imunity.tooltip.TooltipExtension.tooltip;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.vaadin.risto.stepper.IntStepper;

import com.vaadin.data.Binder;
import com.vaadin.data.Validator;
import com.vaadin.server.Sizeable.Unit;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.TextField;

import io.imunity.otp.OTPResetSettings.ConfirmationMode;
import pl.edu.icm.unity.JsonUtil;
import pl.edu.icm.unity.MessageSource;
import pl.edu.icm.unity.engine.api.MessageTemplateManagement;
import pl.edu.icm.unity.engine.api.config.UnityServerConfiguration;
import pl.edu.icm.unity.engine.api.files.FileStorageService;
import pl.edu.icm.unity.engine.api.files.URIAccessService;
import pl.edu.icm.unity.engine.api.utils.PrototypeComponent;
import pl.edu.icm.unity.exceptions.IllegalCredentialException;
import pl.edu.icm.unity.stdext.credential.pass.EmailPasswordResetTemplateDef;
import pl.edu.icm.unity.stdext.credential.pass.MobilePasswordResetTemplateDef;
import pl.edu.icm.unity.webui.common.CompatibleTemplatesComboBox;
import pl.edu.icm.unity.webui.common.EnumComboBox;
import pl.edu.icm.unity.webui.common.FormValidationException;
import pl.edu.icm.unity.webui.common.binding.LocalOrRemoteResource;
import pl.edu.icm.unity.webui.common.credentials.CredentialDefinitionEditor;
import pl.edu.icm.unity.webui.common.file.ImageField;

@PrototypeComponent
class OTPCredentialDefinitionEditor implements CredentialDefinitionEditor
{
	private final int WIDE_FIELD_SIZE_EM = 20;
	private MessageSource msg;
	private Binder binder;
	private MessageTemplateManagement msgTplManagement;
	private IntStepper resetCodeLength;
	private EnumComboBox confirmationMode;
	private CompatibleTemplatesComboBox resetEmailMsgTemplateCombo;
	private CompatibleTemplatesComboBox resetSMSCodeTemplateCombo;
	private CheckBox enableReset;
	private FileStorageService fileStorageService;
	private URIAccessService uriAccessService;
	private UnityServerConfiguration serverConfig;
	
	@Autowired
	OTPCredentialDefinitionEditor(MessageSource msg, MessageTemplateManagement msgTplManagement,
			FileStorageService fileStorageService,
			URIAccessService uriAccessService,  UnityServerConfiguration serverConfig)
	{
		this.msg = msg;
		this.msgTplManagement = msgTplManagement;
		this.fileStorageService = fileStorageService;
		this.uriAccessService = uriAccessService;
		this.serverConfig = serverConfig;
	}

	@Override
	public Component getEditor(String credentialDefinitionConfiguration)
	{
		binder = new Binder<>(OTPDefinitionBean.class);
		
		ImageField logo = new ImageField(msg, uriAccessService, serverConfig.getFileSizeLimit(), true);
		logo.setCaption(msg.getMessage("OTPCredentialDefinitionEditor.logo"));
		tooltip(logo, msg.getMessage("OTPCredentialDefinitionEditor.logo.tip"));
		logo.configureBinding(binder, "logo");
		
		
		TextField issuer = new TextField(msg.getMessage("OTPCredentialDefinitionEditor.issuer"));
		tooltip(issuer, msg.getMessage("OTPCredentialDefinitionEditor.issuer.tip"));
		binder.forField(issuer).asRequired().bind("issuerName");
		
		ComboBox codeLength = new ComboBox<>(msg.getMessage("OTPCredentialDefinitionEditor.codeLength"));
		tooltip(codeLength, msg.getMessage("OTPCredentialDefinitionEditor.codeLength.tip"));
		codeLength.setItems(6, 8);
		codeLength.setEmptySelectionAllowed(false);
		binder.forField(codeLength).asRequired().bind("codeLength");

		IntStepper allowedTimeDrift = new IntStepper(msg.getMessage("OTPCredentialDefinitionEditor.allowedTimeDrift"));
		allowedTimeDrift.setWidth(3, Unit.EM);
		tooltip(allowedTimeDrift, msg.getMessage("OTPCredentialDefinitionEditor.allowedTimeDrift.tip"));
		allowedTimeDrift.setMinValue(0);
		allowedTimeDrift.setMaxValue(2880);
		binder.forField(allowedTimeDrift).asRequired().bind("allowedTimeDriftSteps");
				
		IntStepper timeStep = new IntStepper(msg.getMessage("OTPCredentialDefinitionEditor.timeStep"));
		timeStep.setWidth(3, Unit.EM);
		tooltip(timeStep, msg.getMessage("OTPCredentialDefinitionEditor.timeStep.tip"));
		timeStep.setMinValue(5);
		timeStep.setMaxValue(180);
		binder.forField(timeStep).asRequired().bind("timeStepSeconds");

		EnumComboBox hashAlgorithm = new EnumComboBox<>(
				msg.getMessage("OTPCredentialDefinitionEditor.hashAlgorithm"), 
				msg, "OTPCredentialDefinitionEditor.hashAlgorithm.", HashFunction.class, HashFunction.SHA1);
		tooltip(hashAlgorithm, msg.getMessage("OTPCredentialDefinitionEditor.hashAlgorithm.tip"));
		binder.forField(hashAlgorithm).asRequired().bind("hashFunction");
		
		
		enableReset = new CheckBox(msg.getMessage("OTPCredentialDefinitionEditor.enableReset"));
		binder.forField(enableReset).bind("enableReset");
		enableReset.addValueChangeListener(e -> updateResetState());
		
		confirmationMode = new EnumComboBox<>(
				msg.getMessage("OTPCredentialDefinitionEditor.resetConfirmationMode"), msg, 
				"OTPResetSettingsConfirmationMode.", ConfirmationMode.class, ConfirmationMode.EMAIL);
		binder.forField(confirmationMode).bind("confirmationMode");
		confirmationMode.addValueChangeListener(e -> changeMsgTemplateState());
		confirmationMode.setWidth(WIDE_FIELD_SIZE_EM, Unit.EM);
		
		resetCodeLength = new IntStepper(msg.getMessage("OTPCredentialDefinitionEditor.resetCodeLength"));
		resetCodeLength.setWidth(3, Unit.EM);
		resetCodeLength.setMinValue(1);
		resetCodeLength.setMaxValue(16);
		binder.forField(resetCodeLength).asRequired().bind("resetCodeLength");
		
		resetEmailMsgTemplateCombo = new CompatibleTemplatesComboBox(
				EmailPasswordResetTemplateDef.NAME, msgTplManagement);
		resetEmailMsgTemplateCombo.setDefaultValue();
		resetEmailMsgTemplateCombo.setCaption(msg.getMessage("OTPCredentialDefinitionEditor.emailResetTemaplate"));
		binder.forField(resetEmailMsgTemplateCombo)
			.asRequired(Validator.from(arg -> !(isNullOrEmpty(arg) && enableReset.getValue() 
						&& confirmationMode.getValue().requiresEmailConfirmation()), 
				msg.getMessage("fieldRequired")))
			.bind("emailSecurityCodeMsgTemplate");
		resetEmailMsgTemplateCombo.setWidth(WIDE_FIELD_SIZE_EM, Unit.EM);

		resetSMSCodeTemplateCombo = new CompatibleTemplatesComboBox(
				MobilePasswordResetTemplateDef.NAME, msgTplManagement);
		resetSMSCodeTemplateCombo.setDefaultValue();
		resetSMSCodeTemplateCombo.setCaption(msg.getMessage("OTPCredentialDefinitionEditor.mobileResetTemaplate"));
		binder.forField(resetSMSCodeTemplateCombo)
			.asRequired(Validator.from(arg -> !(isNullOrEmpty(arg) && enableReset.getValue() 
					&& confirmationMode.getValue().requiresMobileConfirmation()), 
			msg.getMessage("fieldRequired")))
			.bind("mobileSecurityCodeMsgTemplate");
		resetSMSCodeTemplateCombo.setWidth(WIDE_FIELD_SIZE_EM, Unit.EM);
		
		updateResetState();
		
		if (credentialDefinitionConfiguration != null)
		{
			OTPCredentialDefinition editedValue = JsonUtil.parse(credentialDefinitionConfiguration, 
				OTPCredentialDefinition.class);
			binder.setBean(OTPDefinitionBean.fromOTPDefinition(editedValue));
		} else
		{
			binder.setBean(new OTPDefinitionBean());
		}
		FormLayout form = new FormLayout(logo, issuer, allowedTimeDrift, timeStep, codeLength, hashAlgorithm,  
				enableReset, confirmationMode, resetCodeLength, 
				resetEmailMsgTemplateCombo, resetSMSCodeTemplateCombo);
		form.setSpacing(true);
		form.setMargin(true);
		return form;
	}

	private void updateResetState()
	{
		boolean enabled = enableReset.getValue();
		resetCodeLength.setEnabled(enabled);
		confirmationMode.setEnabled(enabled);
		changeMsgTemplateState();
	}

	private void changeMsgTemplateState()
	{
		boolean enabled = enableReset.getValue();
		ConfirmationMode mode = confirmationMode.getValue();
		resetEmailMsgTemplateCombo.setEnabled(enabled && mode.isEmail());
		resetSMSCodeTemplateCombo.setEnabled(enabled && mode.isMobile());
	}

	
	@Override
	public String getCredentialDefinition() throws IllegalCredentialException
	{
		if (binder.validate().hasErrors())
			throw new IllegalCredentialException("", new FormValidationException());	
		OTPDefinitionBean configBean = binder.getBean();
		return JsonUtil.toJsonString(configBean.toOTPDefinition("", fileStorageService));
	}
	

	public static class OTPDefinitionBean
	{
		private int codeLength = 6;
		private HashFunction hashFunction = HashFunction.SHA1;
		private int timeStepSeconds = 30;
		private String issuerName = "Unity";
		private int allowedTimeDriftSteps = 3;

		private boolean enableReset = false;
		private int resetCodeLength = 6;
		private String emailSecurityCodeMsgTemplate;
		private String mobileSecurityCodeMsgTemplate;
		private ConfirmationMode confirmationMode = ConfirmationMode.EMAIL;
		private LocalOrRemoteResource logo = new LocalOrRemoteResource();
		
		private static OTPDefinitionBean fromOTPDefinition(OTPCredentialDefinition src)
		{
			OTPDefinitionBean ret = new OTPDefinitionBean();
			ret.allowedTimeDriftSteps = src.allowedTimeDriftSteps;
			ret.codeLength = src.otpParams.codeLength;
			ret.hashFunction = src.otpParams.hashFunction;
			ret.issuerName = src.issuerName;
			ret.timeStepSeconds = src.otpParams.timeStepSeconds;
			ret.enableReset = src.resetSettings.enabled;
			ret.resetCodeLength = src.resetSettings.codeLength;
			ret.emailSecurityCodeMsgTemplate = src.resetSettings.emailSecurityCodeMsgTemplate;
			ret.mobileSecurityCodeMsgTemplate = src.resetSettings.mobileSecurityCodeMsgTemplate;
			ret.confirmationMode = src.resetSettings.confirmationMode;
			ret.logo = new LocalOrRemoteResource(src.logoURI.orElse(null));
			return ret;
		}

		private OTPCredentialDefinition toOTPDefinition(String name, FileStorageService fileStorageService)
		{
			OTPResetSettings resetSettings = new OTPResetSettings(enableReset, resetCodeLength, 
					emailSecurityCodeMsgTemplate, mobileSecurityCodeMsgTemplate, confirmationMode);
			return new OTPCredentialDefinition(
					new OTPGenerationParams(codeLength, hashFunction, timeStepSeconds), 
					issuerName, allowedTimeDriftSteps, resetSettings, Optional.ofNullable(logo.getRemote()));
		}
		
		public int getCodeLength()
		{
			return codeLength;
		}
		public void setCodeLength(int codeLength)
		{
			this.codeLength = codeLength;
		}
		public HashFunction getHashFunction()
		{
			return hashFunction;
		}
		public void setHashFunction(HashFunction hashFunction)
		{
			this.hashFunction = hashFunction;
		}
		public int getTimeStepSeconds()
		{
			return timeStepSeconds;
		}
		public void setTimeStepSeconds(int timeStepSeconds)
		{
			this.timeStepSeconds = timeStepSeconds;
		}
		public String getIssuerName()
		{
			return issuerName;
		}
		public void setIssuerName(String issuerName)
		{
			this.issuerName = issuerName;
		}
		public int getAllowedTimeDriftSteps()
		{
			return allowedTimeDriftSteps;
		}
		public void setAllowedTimeDriftSteps(int allowedTimeDriftSteps)
		{
			this.allowedTimeDriftSteps = allowedTimeDriftSteps;
		}

		public boolean isEnableReset()
		{
			return enableReset;
		}

		public void setEnableReset(boolean enableReset)
		{
			this.enableReset = enableReset;
		}

		public int getResetCodeLength()
		{
			return resetCodeLength;
		}

		public void setResetCodeLength(int resetCodeLength)
		{
			this.resetCodeLength = resetCodeLength;
		}

		public String getEmailSecurityCodeMsgTemplate()
		{
			return emailSecurityCodeMsgTemplate;
		}

		public void setEmailSecurityCodeMsgTemplate(String emailSecurityCodeMsgTemplate)
		{
			this.emailSecurityCodeMsgTemplate = emailSecurityCodeMsgTemplate;
		}

		public String getMobileSecurityCodeMsgTemplate()
		{
			return mobileSecurityCodeMsgTemplate;
		}

		public void setMobileSecurityCodeMsgTemplate(String mobileSecurityCodeMsgTemplate)
		{
			this.mobileSecurityCodeMsgTemplate = mobileSecurityCodeMsgTemplate;
		}

		public ConfirmationMode getConfirmationMode()
		{
			return confirmationMode;
		}

		public void setConfirmationMode(ConfirmationMode confirmationMode)
		{
			this.confirmationMode = confirmationMode;
		}

		public LocalOrRemoteResource getLogo()
		{
			return logo;
		}

		public void setLogo(LocalOrRemoteResource logo)
		{
			this.logo = logo;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy