/*
* 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.http.servlet.helpdesk;
import com.novell.ldapchai.exception.ChaiOperationException;
import com.novell.ldapchai.exception.ChaiUnavailableException;
import password.pwm.AppProperty;
import password.pwm.PwmApplication;
import password.pwm.bean.UserIdentity;
import password.pwm.config.option.IdentityVerificationMethod;
import password.pwm.error.PwmUnrecoverableException;
import password.pwm.http.PwmRequest;
import password.pwm.ldap.LdapOperationsHelper;
import password.pwm.util.java.JsonUtil;
import password.pwm.util.java.TimeDuration;
import password.pwm.util.logging.PwmLogger;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
class HelpdeskVerificationStateBean implements Serializable {
private static final PwmLogger LOGGER = PwmLogger.forClass(HelpdeskVerificationStateBean.class);
private final UserIdentity actor;
private final List<HelpdeskValidationRecord> records = new ArrayList<>();
public static final String PARAMETER_VERIFICATION_STATE_KEY = "verificationState";
private transient TimeDuration maximumAge;
private HelpdeskVerificationStateBean(final UserIdentity actor) {
this.actor = actor;
}
public UserIdentity getActor() {
return actor;
}
public List<HelpdeskValidationRecord> getRecords() {
return records;
}
public void addRecord(final UserIdentity identity, final IdentityVerificationMethod method) {
purgeOldRecords();
final HelpdeskValidationRecord record = getRecord(identity, method);
if (record != null) {
records.remove(record);
}
records.add(new HelpdeskValidationRecord(new Date(), identity, method));
}
public boolean hasRecord(final UserIdentity identity, final IdentityVerificationMethod method) {
purgeOldRecords();
return getRecord(identity,method) != null;
}
private HelpdeskValidationRecord getRecord(final UserIdentity identity, final IdentityVerificationMethod method) {
for (final HelpdeskValidationRecord record : records) {
if (record.getIdentity().equals(identity) && (method == null || record.getMethod() == method)) {
return record;
}
}
return null;
}
void purgeOldRecords() {
for (final Iterator<HelpdeskValidationRecord> iterator = records.iterator(); iterator.hasNext(); ) {
final HelpdeskValidationRecord record = iterator.next();
final Date timestamp = record.getTimestamp();
final TimeDuration age = TimeDuration.fromCurrent(timestamp);
if (age.isLongerThan(maximumAge)) {
iterator.remove();
}
}
}
List<ViewableValidationRecord> asViewableValidationRecords(final PwmApplication pwmApplication, final Locale locale) throws ChaiOperationException, ChaiUnavailableException, PwmUnrecoverableException {
final Map<Date,ViewableValidationRecord> returnRecords = new TreeMap<>();
for (final HelpdeskValidationRecord record : records) {
final String username = LdapOperationsHelper.readLdapUsernameValue(pwmApplication, record.getIdentity());
final String profile = pwmApplication.getConfig().getLdapProfiles().get(record.getIdentity().getLdapProfileID()).getDisplayName(locale);
final String method = record.getMethod().getLabel(pwmApplication.getConfig(), locale);
returnRecords.put(record.getTimestamp(), new ViewableValidationRecord(record.getTimestamp(), profile, username, method));
}
return Collections.unmodifiableList(new ArrayList<>(returnRecords.values()));
}
static class ViewableValidationRecord implements Serializable {
private Date timestamp;
private String profile;
private String username;
private String method;
ViewableValidationRecord(final Date timestamp, final String profile, final String username, final String method) {
this.timestamp = timestamp;
this.profile = profile;
this.username = username;
this.method = method;
}
public Date getTimestamp() {
return timestamp;
}
public String getProfile() {
return profile;
}
public String getUsername() {
return username;
}
public String getMethod() {
return method;
}
}
static class HelpdeskValidationRecord implements Serializable {
private Date timestamp;
private UserIdentity identity;
private IdentityVerificationMethod method;
HelpdeskValidationRecord(final Date timestamp, final UserIdentity identity, final IdentityVerificationMethod method) {
this.timestamp = timestamp;
this.identity = identity;
this.method = method;
}
public Date getTimestamp() {
return timestamp;
}
public UserIdentity getIdentity() {
return identity;
}
public IdentityVerificationMethod getMethod() {
return method;
}
}
String toClientString(final PwmApplication pwmApplication) throws PwmUnrecoverableException {
return pwmApplication.getSecureService().encryptObjectToString(this);
}
static HelpdeskVerificationStateBean fromClientString(
final PwmRequest pwmRequest,
final String rawValue
)
throws PwmUnrecoverableException
{
final int maxAgeSeconds = Integer.parseInt(pwmRequest.getConfig().readAppProperty(AppProperty.HELPDESK_VERIFICATION_TIMEOUT_SECONDS));
final TimeDuration maxAge = new TimeDuration(maxAgeSeconds, TimeUnit.SECONDS);
final UserIdentity actor = pwmRequest.getUserInfoIfLoggedIn();
HelpdeskVerificationStateBean state = null;
if (rawValue != null && !rawValue.isEmpty()) {
state = pwmRequest.getPwmApplication().getSecureService().decryptObject(rawValue, HelpdeskVerificationStateBean.class);
if (!state.getActor().equals(actor)) {
state = null;
}
}
state = state != null ? state : new HelpdeskVerificationStateBean(actor);
state.maximumAge = maxAge;
state.purgeOldRecords();
LOGGER.debug(pwmRequest, "read current state: " + JsonUtil.serialize(state));
return state;
}
}