/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.ims.qti21.ui; import java.io.File; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.util.StringHelper; import org.olat.core.util.crypto.CryptoUtil; import org.olat.core.util.crypto.X509CertificatePrivateKeyPair; import org.olat.ims.qti21.QTI21Module; import org.olat.ims.qti21.ui.assessment.ValidationXmlSignatureController; import org.springframework.beans.factory.annotation.Autowired; /** * Administration for system-wide settings. * * Initial date: 25.08.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class QTI21AdminController extends FormBasicController { private static final String PASSWORD_PLACEHOLDER = "xOOx32x00x"; private static final String[] onKeys = new String[]{ "on" }; private static final String[] onValues = new String[]{ "" }; private FormLink validationButton; private MultipleSelectionElement mathExtensionEl, digitalSignatureEl; private FileElement certificateEl; private TextElement certificatePasswordEl; private CloseableModalController cmc; private ValidationXmlSignatureController validationCtrl; @Autowired private QTI21Module qtiModule; public QTI21AdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl, "admin"); initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { validationButton = uifactory.addFormLink("validate.xml.signature", formLayout, Link.BUTTON); FormLayoutContainer layoutCont = FormLayoutContainer.createDefaultFormLayout("options", getTranslator()); layoutCont.setRootForm(mainForm); formLayout.add("options", layoutCont); layoutCont.setFormTitle(translate("admin.title")); digitalSignatureEl = uifactory.addCheckboxesHorizontal("digital.signature", "digital.signature", layoutCont, onKeys, onValues); if(qtiModule.isDigitalSignatureEnabled()) { digitalSignatureEl.select(onKeys[0], true); } digitalSignatureEl.setExampleKey("digital.signature.text", null); digitalSignatureEl.addActionListener(FormEvent.ONCHANGE); certificateEl = uifactory.addFileElement(getWindowControl(), "digital.signature.certificate", "digital.signature.certificate", layoutCont); certificateEl.setExampleKey("digital.signature.certificate.example", null); certificateEl.setHelpText(translate("digital.signature.certificate.hint")); if(StringHelper.containsNonWhitespace(qtiModule.getDigitalSignatureCertificate())) { File certificate = qtiModule.getDigitalSignatureCertificateFile(); certificateEl.setInitialFile(certificate); } String certificatePassword = qtiModule.getDigitalSignatureCertificatePassword(); String password = StringHelper.containsNonWhitespace(certificatePassword) ? PASSWORD_PLACEHOLDER : ""; certificatePasswordEl = uifactory.addPasswordElement("digital.signature.certificate.password", "digital.signature.certificate.password", 256, password, layoutCont); mathExtensionEl = uifactory.addCheckboxesHorizontal("math.extension", "math.extension", layoutCont, onKeys, onValues); if(qtiModule.isMathAssessExtensionEnabled()) { mathExtensionEl.select(onKeys[0], true); } mathExtensionEl.setExampleKey("math.extension.text", null); mathExtensionEl.addActionListener(FormEvent.ONCHANGE); FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); layoutCont.add(buttonsCont); uifactory.addFormSubmitButton("save", buttonsCont); } private void updateUI() { certificateEl.setVisible(digitalSignatureEl.isSelected(0)); certificatePasswordEl.setVisible(digitalSignatureEl.isSelected(0)); } @Override protected void doDispose() { // } @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; if(certificateEl.getUploadFile() != null) { File uploadedCertificate = certificateEl.getUploadFile(); if(uploadedCertificate != null && uploadedCertificate.exists()) { validateCertificatePassword(uploadedCertificate); } } else { String password = certificatePasswordEl.getValue(); if(!PASSWORD_PLACEHOLDER.equals(password) && certificateEl.getInitialFile() != null) { validateCertificatePassword(certificateEl.getInitialFile()); } } return allOk & super.validateFormLogic(ureq); } private boolean validateCertificatePassword(File file) { boolean allOk = true; try { String password = certificatePasswordEl.getValue(); X509CertificatePrivateKeyPair kp = CryptoUtil.getX509CertificatePrivateKeyPairPfx(file, password); if(kp.getX509Cert() == null) { certificateEl.setErrorKey("error.digital.certificate.noX509", null); allOk &= false; } else if(kp.getPrivateKey() == null) { certificateEl.setErrorKey("error.digital.certificate.noPrivateKey", null); allOk &= false; } } catch (Exception e) { logError("", e); String message = e.getMessage() == null ? "" : e.getMessage(); String [] errorArgs = new String[]{ message }; certificateEl.setErrorKey("error.digital.certificate.cannotread", errorArgs); allOk &= false; } return allOk; } @Override protected void event(UserRequest ureq, Controller source, Event event) { if(validationCtrl == source) { cmc.deactivate(); cleanUp(); } else if(cmc == source) { cleanUp(); } super.event(ureq, source, event); } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(digitalSignatureEl == source) { updateUI(); } else if(validationButton == source) { doValidate(ureq); } super.formInnerEvent(ureq, source, event); } @Override protected void formOK(UserRequest ureq) { qtiModule.setMathAssessExtensionEnabled(mathExtensionEl.isSelected(0)); qtiModule.setDigitalSignatureEnabled(digitalSignatureEl.isSelected(0)); if(digitalSignatureEl.isSelected(0)) { File uploadedCertificate = certificateEl.getUploadFile(); if(uploadedCertificate != null && uploadedCertificate.exists()) { qtiModule.setDigitalSignatureCertificateFile(uploadedCertificate, certificateEl.getUploadFileName()); File newFile = qtiModule.getDigitalSignatureCertificateFile(); certificateEl.reset();// make sure the same certificate is not load twice certificateEl.setInitialFile(newFile); } String password = certificatePasswordEl.getValue(); if(!PASSWORD_PLACEHOLDER.equals(password)) { qtiModule.setDigitalSignatureCertificatePassword(password); } } } private void cleanUp() { removeAsListenerAndDispose(validationCtrl); removeAsListenerAndDispose(cmc); validationCtrl = null; cmc = null; } private void doValidate(UserRequest ureq) { if(validationCtrl != null) return; validationCtrl = new ValidationXmlSignatureController(ureq, getWindowControl()); listenTo(validationCtrl); cmc = new CloseableModalController(getWindowControl(), "close", validationCtrl.getInitialComponent(), true, translate("validate.xml.signature")); cmc.activate(); listenTo(cmc); } }