package org.apereo.cas.otp.repository.credentials; import org.apache.commons.lang3.StringUtils; import org.apereo.cas.util.serialization.AbstractJacksonBackedStringSerializer; import org.apereo.cas.util.serialization.StringSerializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import java.util.Collection; import java.util.List; import java.util.TreeSet; /** * This is {@link BaseJsonOneTimeTokenCredentialRepository}. * * @author Misagh Moayyed * @since 5.1.0 */ public abstract class BaseJsonOneTimeTokenCredentialRepository extends BaseOneTimeTokenCredentialRepository { private static final Logger LOGGER = LoggerFactory.getLogger(BaseJsonOneTimeTokenCredentialRepository.class); private final Resource location; private final StringSerializer<TreeSet<OneTimeTokenAccount>> serializer = new OneTimeAccountSerializer(); public BaseJsonOneTimeTokenCredentialRepository(final Resource location) { this.location = location; } @Override public String getSecret(final String username) { try { if (!this.location.getFile().exists()) { LOGGER.warn("JSON account repository file [{}] is not found.", this.location.getFile()); return null; } if (this.location.getFile().length() <= 0) { LOGGER.warn("JSON account repository file [{}] is empty.", this.location.getFile()); return null; } final Collection<OneTimeTokenAccount> c = this.serializer.from(this.location.getFile()); return c.stream() .filter(a -> StringUtils.isNotBlank(a.getUsername()) && a.getUsername().equals(username)) .map(OneTimeTokenAccount::getSecretKey) .findAny() .orElse(null); } catch (final Exception e) { LOGGER.error(e.getMessage(), e); } return null; } @Override public void save(final String userName, final String secretKey, final int validationCode, final List<Integer> scratchCodes) { try { LOGGER.debug("Storing google authenticator account for [{}]", userName); final OneTimeTokenAccount account = new OneTimeTokenAccount(userName, secretKey, validationCode, scratchCodes); LOGGER.debug("Ensuring JSON repository file exists at [{}]", this.location.getFile()); this.location.getFile().createNewFile(); final TreeSet<OneTimeTokenAccount> c; if (this.location.getFile().length() > 0) { LOGGER.debug("Reading JSON repository file at [{}]", this.location.getFile()); c = this.serializer.from(this.location.getFile()); } else { c = new TreeSet<>(); } LOGGER.debug("Found [{}] account(s) and added google authenticator account for [{}]", c.size(), userName); c.add(account); LOGGER.debug("Saving google authenticator accounts back to the JSON file at [{}]", this.location.getFile()); this.serializer.to(this.location.getFile(), c); } catch (final Exception e) { LOGGER.error(e.getMessage(), e); } } private static class OneTimeAccountSerializer extends AbstractJacksonBackedStringSerializer<TreeSet<OneTimeTokenAccount>> { private static final long serialVersionUID = 1466569521275630254L; @Override protected Class getTypeToSerialize() { return TreeSet.class; } } }