/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * 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 should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.util.operations.otp; import com.google.gson.JsonSyntaxException; import password.pwm.AppProperty; import password.pwm.PwmApplication; import password.pwm.config.Configuration; import password.pwm.config.PwmSetting; import password.pwm.config.option.OTPStorageFormat; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmOperationalException; import password.pwm.error.PwmUnrecoverableException; import password.pwm.util.java.JavaHelper; import password.pwm.util.java.JsonUtil; import password.pwm.util.logging.PwmLogger; import password.pwm.util.secure.PwmBlockAlgorithm; import password.pwm.util.secure.PwmSecurityKey; import password.pwm.util.secure.SecureEngine; /** * * @author mpieters */ public abstract class AbstractOtpOperator implements OtpOperator { private static final PwmLogger LOGGER = PwmLogger.forClass(AbstractOtpOperator.class); protected PwmApplication pwmApplication; /** * Compose a single line of OTP information. * * @param otpUserRecord * @return * @throws password.pwm.error.PwmUnrecoverableException */ public String composeOtpAttribute(final OTPUserRecord otpUserRecord) throws PwmUnrecoverableException { String value = ""; if (otpUserRecord != null) { final Configuration config = pwmApplication.getConfig(); final OTPStorageFormat format = config.readSettingAsEnum(PwmSetting.OTP_SECRET_STORAGEFORMAT,OTPStorageFormat.class); switch (format) { case PWM: value = JsonUtil.serialize(otpUserRecord); break; case OTPURL: value = OTPUrlUtil.composeOtpUrl(otpUserRecord); break; case BASE32SECRET: value = otpUserRecord.getSecret(); break; case PAM: value = OTPPamUtil.composePamData(otpUserRecord); break; default: final String errorStr = String.format("Unsupported storage format: ", format.toString()); final ErrorInformation error = new ErrorInformation(PwmError.ERROR_INVALID_CONFIG, errorStr); throw new PwmUnrecoverableException(error); } } return value; } /** * Encrypt the given string using the PWM encryption key. * * @param unencrypted * @return * @throws PwmUnrecoverableException * @throws PwmOperationalException */ public String encryptAttributeValue(final String unencrypted) throws PwmUnrecoverableException, PwmOperationalException { final PwmBlockAlgorithm pwmBlockAlgorithm = figureBlockAlg(); final PwmSecurityKey pwmSecurityKey = pwmApplication.getConfig().getSecurityKey(); return SecureEngine.encryptToString(unencrypted, pwmSecurityKey, pwmBlockAlgorithm); } public PwmBlockAlgorithm figureBlockAlg() { final String otpEncryptionAlgString = pwmApplication.getConfig().readAppProperty(AppProperty.OTP_ENCRYPTION_ALG); return JavaHelper.readEnumFromString(PwmBlockAlgorithm.class, PwmBlockAlgorithm.AES, otpEncryptionAlgString); } /** * Decrypt the given string using the PWM encryption key. * * @param encrypted * @return * @throws PwmUnrecoverableException * @throws PwmOperationalException */ public String decryptAttributeValue(final String encrypted) throws PwmUnrecoverableException, PwmOperationalException { final PwmBlockAlgorithm pwmBlockAlgorithm = figureBlockAlg(); final PwmSecurityKey pwmSecurityKey = pwmApplication.getConfig().getSecurityKey(); return SecureEngine.decryptStringValue(encrypted, pwmSecurityKey, pwmBlockAlgorithm); } /** * * @param value * @return */ public OTPUserRecord decomposeOtpAttribute(final String value) { if (value == null) { return null; } OTPUserRecord otpconfig = null; /* Try format by format */ LOGGER.trace(String.format("detecting format from value: %s", value)); /* - PWM JSON */ try { otpconfig = JsonUtil.deserialize(value, OTPUserRecord.class); LOGGER.debug("detected JSON format - returning"); return otpconfig; } catch (JsonSyntaxException ex) { LOGGER.debug("no JSON format detected - returning"); /* So, it's not JSON, try something else */ /* -- nothing to try, yet; for future use */ /* no more options */ } /* - otpauth:// URL */ otpconfig = OTPUrlUtil.decomposeOtpUrl(value); if (otpconfig != null) { LOGGER.debug("detected otpauth URL format - returning"); return otpconfig; } /* - PAM */ otpconfig = OTPPamUtil.decomposePamData(value); if (otpconfig != null) { LOGGER.debug("detected PAM text format - returning"); return otpconfig; } /* - BASE32 secret */ if (value.trim().matches("^[A-Z2-7\\=]{16}$")) { LOGGER.debug("detected plain Base32 secret - returning"); otpconfig = new OTPUserRecord(); otpconfig.setSecret(value.trim()); return otpconfig; } return otpconfig; } public PwmApplication getPwmApplication() { return pwmApplication; } public void setPwmApplication(final PwmApplication pwmApplication) { this.pwmApplication = pwmApplication; } }