Преглед изворни кода

config authentication improvements

Jason Rivard пре 6 година
родитељ
комит
ea2f4f1c14

+ 3 - 1
server/src/main/java/password/pwm/http/PwmURL.java

@@ -34,6 +34,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
+import java.util.Objects;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
 public class PwmURL
 public class PwmURL
@@ -48,7 +49,8 @@ public class PwmURL
             final String contextPath
             final String contextPath
     )
     )
     {
     {
-        this.uri = uri;
+        Objects.requireNonNull( uri );
+        this.uri = uri.normalize();
         this.contextPath = contextPath;
         this.contextPath = contextPath;
     }
     }
 
 

+ 10 - 296
server/src/main/java/password/pwm/http/filter/ConfigAccessFilter.java

@@ -20,58 +20,34 @@
 
 
 package password.pwm.http.filter;
 package password.pwm.http.filter;
 
 
-import com.google.gson.annotations.SerializedName;
-import lombok.Value;
 import password.pwm.AppProperty;
 import password.pwm.AppProperty;
 import password.pwm.Permission;
 import password.pwm.Permission;
-import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
 import password.pwm.PwmApplicationMode;
-import password.pwm.PwmConstants;
-import password.pwm.bean.UserIdentity;
-import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.ConfigurationReader;
 import password.pwm.config.stored.ConfigurationReader;
-import password.pwm.config.stored.StoredConfiguration;
 import password.pwm.config.stored.StoredConfigurationImpl;
 import password.pwm.config.stored.StoredConfigurationImpl;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.ContextManager;
 import password.pwm.http.ContextManager;
-import password.pwm.http.JspUrl;
 import password.pwm.http.ProcessStatus;
 import password.pwm.http.ProcessStatus;
-import password.pwm.http.PwmHttpResponseWrapper;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmRequest;
-import password.pwm.http.PwmRequestAttribute;
-import password.pwm.http.PwmSession;
 import password.pwm.http.PwmURL;
 import password.pwm.http.PwmURL;
 import password.pwm.http.bean.ConfigManagerBean;
 import password.pwm.http.bean.ConfigManagerBean;
-import password.pwm.svc.intruder.RecordType;
+import password.pwm.http.servlet.PwmServletDefinition;
 import password.pwm.svc.sessiontrack.UserAgentUtils;
 import password.pwm.svc.sessiontrack.UserAgentUtils;
-import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.StringUtil;
-import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
-import password.pwm.util.secure.PwmHashAlgorithm;
-import password.pwm.util.secure.SecureEngine;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
 import java.io.IOException;
 import java.io.IOException;
-import java.io.Serializable;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 
 
 public class ConfigAccessFilter extends AbstractPwmFilter
 public class ConfigAccessFilter extends AbstractPwmFilter
 {
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( ConfigAccessFilter.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( ConfigAccessFilter.class );
 
 
-    private static final String COOKIE_NAME = PwmConstants.COOKIE_PERSISTENT_CONFIG_LOGIN;
-    private static final PwmHttpResponseWrapper.CookiePath COOKIE_PATH = PwmHttpResponseWrapper.CookiePath.Private;
-
     @Override
     @Override
-    void processFilter( final PwmApplicationMode mode, final PwmRequest pwmRequest, final PwmFilterChain filterChain ) throws PwmException, IOException, ServletException
+    void processFilter( final PwmApplicationMode mode, final PwmRequest pwmRequest, final PwmFilterChain filterChain )
+            throws PwmException, IOException, ServletException
     {
     {
         final PwmApplicationMode appMode = pwmRequest.getPwmApplication().getApplicationMode();
         final PwmApplicationMode appMode = pwmRequest.getPwmApplication().getApplicationMode();
         if ( appMode == PwmApplicationMode.NEW )
         if ( appMode == PwmApplicationMode.NEW )
@@ -111,17 +87,15 @@ public class ConfigAccessFilter extends AbstractPwmFilter
     @Override
     @Override
     boolean isInterested( final PwmApplicationMode mode, final PwmURL pwmURL )
     boolean isInterested( final PwmApplicationMode mode, final PwmURL pwmURL )
     {
     {
-        return pwmURL.isConfigManagerURL();
+        return true;
     }
     }
 
 
-    private static ProcessStatus checkAuthentication(
+    public static ProcessStatus checkAuthentication(
             final PwmRequest pwmRequest,
             final PwmRequest pwmRequest,
             final ConfigManagerBean configManagerBean
             final ConfigManagerBean configManagerBean
     )
     )
             throws IOException, PwmUnrecoverableException, ServletException
             throws IOException, PwmUnrecoverableException, ServletException
     {
     {
-        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
-        final PwmSession pwmSession = pwmRequest.getPwmSession();
         final ConfigurationReader runningConfigReader = ContextManager.getContextManager( pwmRequest.getHttpServletRequest().getSession() ).getConfigReader();
         final ConfigurationReader runningConfigReader = ContextManager.getContextManager( pwmRequest.getHttpServletRequest().getSession() ).getConfigReader();
         final StoredConfigurationImpl storedConfig = runningConfigReader.getStoredConfiguration();
         final StoredConfigurationImpl storedConfig = runningConfigReader.getStoredConfiguration();
 
 
@@ -132,117 +106,15 @@ public class ConfigAccessFilter extends AbstractPwmFilter
             return ProcessStatus.Continue;
             return ProcessStatus.Continue;
         }
         }
 
 
-        final boolean persistentLoginEnabled = persistentLoginEnabled( pwmRequest );
-
-        if ( persistentLoginEnabled )
-        {
-            final boolean persistentLoginPassed = checkPersistentLoginCookie( pwmRequest, storedConfig );
-            if ( persistentLoginPassed )
-            {
-                return processLoginSuccess( pwmRequest, persistentLoginEnabled );
-            }
-        }
-
-        final String password = pwmRequest.readParameterAsString( "password" );
-
-        boolean passwordAccepted = false;
-        if ( !StringUtil.isEmpty( password ) )
-        {
-            if ( storedConfig.verifyPassword( password, pwmRequest.getConfig() ) )
-            {
-                passwordAccepted = true;
-                LOGGER.trace( pwmRequest, () -> "valid configuration password accepted" );
-                updateLoginHistory( pwmRequest, pwmRequest.getUserInfoIfLoggedIn(), true );
-            }
-            else
-            {
-                LOGGER.trace( pwmRequest, () -> "configuration password is not correct" );
-                pwmApplication.getIntruderManager().convenience().markAddressAndSession( pwmSession );
-                pwmApplication.getIntruderManager().mark( RecordType.USERNAME, PwmConstants.CONFIGMANAGER_INTRUDER_USERNAME, pwmSession.getLabel() );
-                final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_PASSWORD_ONLY_BAD );
-                updateLoginHistory( pwmRequest, pwmRequest.getUserInfoIfLoggedIn(), false );
-                return denyAndError( pwmRequest, errorInformation );
-            }
-        }
-
-        if ( passwordAccepted )
+        if ( !pwmRequest.getURL().isPwmServletURL( PwmServletDefinition.ConfigManager_Login ) )
         {
         {
-            return processLoginSuccess( pwmRequest, persistentLoginEnabled );
-        }
-
-        configManagerBean.setPrePasswordEntryUrl( pwmRequest.getHttpServletRequest().getRequestURL().toString() );
-
-        forwardToJsp( pwmRequest );
-        return ProcessStatus.Halt;
-    }
-
-    private static void writePersistentLoginCookie( final PwmRequest pwmRequest )
-            throws PwmUnrecoverableException
-    {
-        final int persistentSeconds = figureMaxLoginSeconds( pwmRequest );
-
-        if ( persistentSeconds > 0 )
-        {
-            final TimeDuration persistenceDuration = TimeDuration.of( persistentSeconds, TimeDuration.Unit.SECONDS );
-            final Instant expirationDate = persistenceDuration.incrementFromInstant( Instant.now() );
-            final StoredConfigurationImpl storedConfig = pwmRequest.getConfig().getStoredConfiguration();
-            final String persistentLoginValue = makePersistentLoginPassword( pwmRequest, storedConfig );
-            final PersistentLoginInfo persistentLoginInfo = new PersistentLoginInfo( expirationDate, persistentLoginValue );
-            final String cookieValue = pwmRequest.getPwmApplication().getSecureService().encryptObjectToString( persistentLoginInfo );
-            pwmRequest.getPwmResponse().writeCookie(
-                    COOKIE_NAME,
-                    cookieValue,
-                    persistentSeconds,
-                    COOKIE_PATH
-            );
-            LOGGER.debug( pwmRequest, () -> "set persistent config login cookie (expires "
-                    + JavaHelper.toIsoDate( expirationDate )
-                    + ")"
-            );
-        }
-    }
-
-    private static boolean checkPersistentLoginCookie(
-            final PwmRequest pwmRequest,
-            final StoredConfiguration storedConfig
-
-    )
-    {
-        try
-        {
-            final String cookieValue = pwmRequest.readCookie( COOKIE_NAME );
-            if ( !StringUtil.isEmpty( cookieValue ) )
-            {
-                final PersistentLoginInfo persistentLoginInfo = pwmRequest.getPwmApplication().getSecureService().decryptObject( cookieValue, PersistentLoginInfo.class );
-                if ( persistentLoginInfo != null )
-                {
-                    if ( persistentLoginInfo.getExpireDate().isAfter( Instant.now() ) )
-                    {
-                        final String persistentLoginPassword = makePersistentLoginPassword( pwmRequest, storedConfig );
-                        if ( StringUtil.nullSafeEquals( persistentLoginPassword, persistentLoginInfo.getPassword() ) )
-                        {
-                            LOGGER.debug( pwmRequest, () -> "accepting persistent config login from cookie (expires "
-                                    + JavaHelper.toIsoDate( persistentLoginInfo.getExpireDate() )
-                                    + ")"
-                            );
-                            return true;
-                        }
-                    }
-
-                    pwmRequest.getPwmResponse().removeCookie( COOKIE_NAME, COOKIE_PATH );
-                    LOGGER.debug( pwmRequest, () -> "removing non-working persistent config login cookie" );
-                }
-            }
-        }
-        catch ( Exception e )
-        {
-            LOGGER.error( pwmRequest, "error examining persistent config login cookie: " + e.getMessage() );
+            configManagerBean.setPrePasswordEntryUrl( pwmRequest.getHttpServletRequest().getRequestURL().toString() );
+            pwmRequest.sendRedirect( PwmServletDefinition.ConfigManager_Login );
+            return ProcessStatus.Halt;
         }
         }
-
-        return false;
+        return ProcessStatus.Continue;
     }
     }
 
 
-
     private static void checkPreconditions(
     private static void checkPreconditions(
             final PwmRequest pwmRequest,
             final PwmRequest pwmRequest,
             final StoredConfigurationImpl storedConfig
             final StoredConfigurationImpl storedConfig
@@ -272,164 +144,6 @@ public class ConfigAccessFilter extends AbstractPwmFilter
             {
             {
                 throw new PwmUnrecoverableException( PwmError.ERROR_UNAUTHORIZED );
                 throw new PwmUnrecoverableException( PwmError.ERROR_UNAUTHORIZED );
             }
             }
-         }
-    }
-
-    private static boolean persistentLoginEnabled(
-            final PwmRequest pwmRequest
-    )
-    {
-        if ( pwmRequest.getConfig().isDefaultValue( PwmSetting.PWM_SECURITY_KEY ) )
-        {
-            LOGGER.debug( pwmRequest, () -> "security not available, persistent login not possible." );
-            return false;
         }
         }
-
-        return true;
-    }
-
-    private static String makePersistentLoginPassword(
-            final PwmRequest pwmRequest,
-            final StoredConfiguration storedConfig
-    )
-            throws PwmUnrecoverableException
-    {
-        final int hashChars = 32;
-        String hashValue = storedConfig.readConfigProperty( ConfigurationProperty.PASSWORD_HASH );
-
-        if ( PwmApplicationMode.RUNNING == pwmRequest.getPwmApplication().getApplicationMode() )
-        {
-            final PwmSession pwmSession = pwmRequest.getPwmSession();
-            hashValue += pwmSession.getUserInfo().getUserIdentity().toDelimitedKey();
-        }
-
-        return StringUtil.truncate( SecureEngine.hash( hashValue, PwmHashAlgorithm.SHA512 ), hashChars );
-    }
-
-    private static void forwardToJsp( final PwmRequest pwmRequest )
-            throws ServletException, PwmUnrecoverableException, IOException
-    {
-        final int persistentSeconds = figureMaxLoginSeconds( pwmRequest );
-        final String time = TimeDuration.of( persistentSeconds, TimeDuration.Unit.SECONDS ).asLongString( pwmRequest.getLocale() );
-
-        final ConfigLoginHistory configLoginHistory = readConfigLoginHistory( pwmRequest );
-
-        pwmRequest.setAttribute( PwmRequestAttribute.ConfigLoginHistory, configLoginHistory );
-        pwmRequest.setAttribute( PwmRequestAttribute.ConfigPasswordRememberTime, time );
-        pwmRequest.forwardToJsp( JspUrl.CONFIG_MANAGER_LOGIN );
-
-    }
-
-    private static ConfigLoginHistory readConfigLoginHistory( final PwmRequest pwmRequest )
-    {
-        final ConfigLoginHistory configLoginHistory = pwmRequest.getPwmApplication().readAppAttribute( PwmApplication.AppAttribute.CONFIG_LOGIN_HISTORY, ConfigLoginHistory.class );
-        return configLoginHistory == null
-                ? new ConfigLoginHistory()
-                : configLoginHistory;
-    }
-
-    private static void updateLoginHistory( final PwmRequest pwmRequest, final UserIdentity userIdentity, final boolean successful )
-    {
-        final ConfigLoginHistory configLoginHistory = readConfigLoginHistory( pwmRequest );
-        final ConfigLoginEvent event = new ConfigLoginEvent(
-                userIdentity == null ? "n/a" : userIdentity.toDisplayString(),
-                Instant.now(),
-                pwmRequest.getPwmSession().getSessionStateBean().getSrcAddress()
-        );
-        final int maxEvents = Integer.parseInt( pwmRequest.getPwmApplication().getConfig().readAppProperty( AppProperty.CONFIG_HISTORY_MAX_ITEMS ) );
-        configLoginHistory.addEvent( event, maxEvents, successful );
-        pwmRequest.getPwmApplication().writeAppAttribute( PwmApplication.AppAttribute.CONFIG_LOGIN_HISTORY, configLoginHistory );
-    }
-
-    @Value
-    private static class PersistentLoginInfo implements Serializable
-    {
-        @SerializedName( "e" )
-        private Instant expireDate;
-
-        @SerializedName( "p" )
-        private String password;
-    }
-
-    @Value
-    public static class ConfigLoginHistory implements Serializable
-    {
-        private List<ConfigLoginEvent> successEvents = new ArrayList<>();
-        private List<ConfigLoginEvent> failedEvents = new ArrayList<>();
-
-        void addEvent( final ConfigLoginEvent event, final int maxEvents, final boolean successful )
-        {
-            final List<ConfigLoginEvent> events = successful ? successEvents : failedEvents;
-            events.add( event );
-            if ( maxEvents > 0 )
-            {
-                while ( events.size() > maxEvents )
-                {
-                    events.remove( 0 );
-                }
-            }
-        }
-
-        public List<ConfigLoginEvent> successEvents( )
-        {
-            return Collections.unmodifiableList( successEvents );
-        }
-
-        public List<ConfigLoginEvent> failedEvents( )
-        {
-            return Collections.unmodifiableList( failedEvents );
-        }
-    }
-
-    @Value
-    public static class ConfigLoginEvent implements Serializable
-    {
-        private final String userIdentity;
-        private final Instant date;
-        private final String networkAddress;
-    }
-
-    private static int figureMaxLoginSeconds( final PwmRequest pwmRequest )
-    {
-        return JavaHelper.silentParseInt(
-                pwmRequest.getConfig().readAppProperty( AppProperty.CONFIG_MAX_PERSISTENT_LOGIN_SECONDS ),
-                (int) TimeDuration.HOUR.as( TimeDuration.Unit.SECONDS )
-        );
-    }
-
-
-    private static ProcessStatus denyAndError( final PwmRequest pwmRequest, final ErrorInformation errorInformation )
-            throws ServletException, PwmUnrecoverableException, IOException
-    {
-        pwmRequest.respondWithError( errorInformation );
-        return ProcessStatus.Halt;
-    }
-
-    private static ProcessStatus processLoginSuccess( final PwmRequest pwmRequest, final boolean persistentLoginEnabled )
-            throws PwmUnrecoverableException, IOException
-    {
-        final ConfigManagerBean configManagerBean = pwmRequest.getPwmApplication().getSessionStateService().getBean( pwmRequest, ConfigManagerBean.class );
-        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
-        final PwmSession pwmSession = pwmRequest.getPwmSession();
-
-        configManagerBean.setPasswordVerified( true );
-        pwmApplication.getIntruderManager().convenience().clearAddressAndSession( pwmSession );
-        pwmApplication.getIntruderManager().clear( RecordType.USERNAME, PwmConstants.CONFIGMANAGER_INTRUDER_USERNAME );
-        pwmRequest.getPwmSession().getSessionStateBean().setSessionIdRecycleNeeded( true );
-        if ( persistentLoginEnabled && "on".equals( pwmRequest.readParameterAsString( "remember" ) ) )
-        {
-            writePersistentLoginCookie( pwmRequest );
-        }
-
-        if ( configManagerBean.getPrePasswordEntryUrl() != null )
-        {
-            final String originalUrl = configManagerBean.getPrePasswordEntryUrl();
-            configManagerBean.setPrePasswordEntryUrl( null );
-            pwmRequest.getPwmResponse().sendRedirect( originalUrl );
-            return ProcessStatus.Halt;
-        }
-
-        pwmRequest.sendRedirect( pwmRequest.getURLwithQueryString() );
-        return ProcessStatus.Continue;
     }
     }
 }
 }

+ 2 - 0
server/src/main/java/password/pwm/http/servlet/PwmServletDefinition.java

@@ -48,6 +48,7 @@ import password.pwm.http.servlet.configeditor.ConfigEditorServlet;
 import password.pwm.http.servlet.configguide.ConfigGuideServlet;
 import password.pwm.http.servlet.configguide.ConfigGuideServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerCertificatesServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerCertificatesServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerLocalDBServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerLocalDBServlet;
+import password.pwm.http.servlet.configmanager.ConfigManagerLoginServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerWordlistServlet;
 import password.pwm.http.servlet.configmanager.ConfigManagerWordlistServlet;
 import password.pwm.http.servlet.newuser.NewUserServlet;
 import password.pwm.http.servlet.newuser.NewUserServlet;
@@ -90,6 +91,7 @@ public enum PwmServletDefinition
     ConfigGuide( ConfigGuideServlet.class, ConfigGuideBean.class ),
     ConfigGuide( ConfigGuideServlet.class, ConfigGuideBean.class ),
     ConfigEditor( ConfigEditorServlet.class, null ),
     ConfigEditor( ConfigEditorServlet.class, null ),
     ConfigManager( ConfigManagerServlet.class, ConfigManagerBean.class ),
     ConfigManager( ConfigManagerServlet.class, ConfigManagerBean.class ),
+    ConfigManager_Login( ConfigManagerLoginServlet.class, ConfigManagerBean.class ),
     ConfigManager_Wordlists( ConfigManagerWordlistServlet.class, ConfigManagerBean.class ),
     ConfigManager_Wordlists( ConfigManagerWordlistServlet.class, ConfigManagerBean.class ),
     ConfigManager_LocalDB( ConfigManagerLocalDBServlet.class, ConfigManagerBean.class ),
     ConfigManager_LocalDB( ConfigManagerLocalDBServlet.class, ConfigManagerBean.class ),
     ConfigManager_Certificates( ConfigManagerCertificatesServlet.class, ConfigManagerBean.class ),
     ConfigManager_Certificates( ConfigManagerCertificatesServlet.class, ConfigManagerBean.class ),

+ 5 - 2
server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServlet.java

@@ -72,12 +72,12 @@ import password.pwm.i18n.Message;
 import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.ldap.LdapBrowser;
 import password.pwm.ldap.LdapBrowser;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
-import password.pwm.util.password.RandomPasswordGenerator;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
 import password.pwm.util.macro.MacroMachine;
+import password.pwm.util.password.RandomPasswordGenerator;
 import password.pwm.util.queue.SmsQueueManager;
 import password.pwm.util.queue.SmsQueueManager;
 import password.pwm.util.secure.HttpsServerCertificateManager;
 import password.pwm.util.secure.HttpsServerCertificateManager;
 import password.pwm.ws.server.RestResultBean;
 import password.pwm.ws.server.RestResultBean;
@@ -164,8 +164,11 @@ public class ConfigEditorServlet extends ControlledPwmServlet
     }
     }
 
 
     @Override
     @Override
-    public ProcessStatus preProcessCheck( final PwmRequest pwmRequest ) throws PwmUnrecoverableException, IOException, ServletException
+    public ProcessStatus preProcessCheck( final PwmRequest pwmRequest )
+            throws PwmUnrecoverableException, IOException, ServletException
     {
     {
+        ConfigManagerServlet.verifyConfigAccess( pwmRequest );
+
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
 
 
         if ( configManagerBean.getStoredConfiguration() == null )
         if ( configManagerBean.getStoredConfiguration() == null )

+ 2 - 0
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerCertificatesServlet.java

@@ -98,6 +98,8 @@ public class ConfigManagerCertificatesServlet extends AbstractPwmServlet
     protected void processAction( final PwmRequest pwmRequest )
     protected void processAction( final PwmRequest pwmRequest )
             throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
             throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
     {
     {
+        ConfigManagerServlet.verifyConfigAccess( pwmRequest );
+
         final ConfigManagerCertificateAction action = readProcessAction( pwmRequest );
         final ConfigManagerCertificateAction action = readProcessAction( pwmRequest );
         final ArrayList<CertificateDebugDataItem> certificateDebugDataItems = new ArrayList<>( makeCertificateDebugData( pwmRequest.getConfig() ) );
         final ArrayList<CertificateDebugDataItem> certificateDebugDataItems = new ArrayList<>( makeCertificateDebugData( pwmRequest.getConfig() ) );
 
 

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerLocalDBServlet.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.http.servlet.configmanager;
 package password.pwm.http.servlet.configmanager;
 
 
-import com.novell.ldapchai.exception.ChaiUnavailableException;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 import password.pwm.AppProperty;
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmApplication;
@@ -103,8 +102,9 @@ public class ConfigManagerLocalDBServlet extends AbstractPwmServlet
     }
     }
 
 
     protected void processAction( final PwmRequest pwmRequest )
     protected void processAction( final PwmRequest pwmRequest )
-            throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
+            throws ServletException, IOException, PwmUnrecoverableException
     {
     {
+        ConfigManagerServlet.verifyConfigAccess( pwmRequest );
 
 
         final ConfigManagerAction processAction = readProcessAction( pwmRequest );
         final ConfigManagerAction processAction = readProcessAction( pwmRequest );
         if ( processAction != null )
         if ( processAction != null )

+ 420 - 0
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerLoginServlet.java

@@ -0,0 +1,420 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2019 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.http.servlet.configmanager;
+
+import com.google.gson.annotations.SerializedName;
+import com.novell.ldapchai.exception.ChaiUnavailableException;
+import lombok.Value;
+import password.pwm.AppProperty;
+import password.pwm.PwmApplication;
+import password.pwm.PwmApplicationMode;
+import password.pwm.PwmConstants;
+import password.pwm.bean.UserIdentity;
+import password.pwm.config.PwmSetting;
+import password.pwm.config.stored.ConfigurationProperty;
+import password.pwm.config.stored.ConfigurationReader;
+import password.pwm.config.stored.StoredConfiguration;
+import password.pwm.config.stored.StoredConfigurationImpl;
+import password.pwm.error.ErrorInformation;
+import password.pwm.error.PwmError;
+import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.http.ContextManager;
+import password.pwm.http.HttpMethod;
+import password.pwm.http.JspUrl;
+import password.pwm.http.ProcessStatus;
+import password.pwm.http.PwmHttpResponseWrapper;
+import password.pwm.http.PwmRequest;
+import password.pwm.http.PwmRequestAttribute;
+import password.pwm.http.PwmSession;
+import password.pwm.http.bean.ConfigManagerBean;
+import password.pwm.http.servlet.AbstractPwmServlet;
+import password.pwm.http.servlet.PwmServletDefinition;
+import password.pwm.svc.intruder.RecordType;
+import password.pwm.util.java.JavaHelper;
+import password.pwm.util.java.StringUtil;
+import password.pwm.util.java.TimeDuration;
+import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureEngine;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+@WebServlet(
+        name = "ConfigManagerLogin",
+        urlPatterns = {
+                PwmConstants.URL_PREFIX_PRIVATE + "/config/login",
+        }
+)
+public class ConfigManagerLoginServlet extends AbstractPwmServlet
+{
+    private static final PwmLogger LOGGER = PwmLogger.forClass( ConfigManagerLoginServlet.class );
+
+    private static final String COOKIE_NAME = PwmConstants.COOKIE_PERSISTENT_CONFIG_LOGIN;
+    private static final PwmHttpResponseWrapper.CookiePath COOKIE_PATH = PwmHttpResponseWrapper.CookiePath.CurrentURL;
+
+    public enum ConfigManagerLoginAction implements ProcessAction
+    {
+        login( HttpMethod.POST ),;
+
+        private final HttpMethod method;
+
+        ConfigManagerLoginAction( final HttpMethod method )
+        {
+            this.method = method;
+        }
+
+        public Collection<HttpMethod> permittedMethods( )
+        {
+            return Collections.singletonList( method );
+        }
+    }
+
+    @Override
+    protected void processAction( final PwmRequest pwmRequest )
+            throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
+    {
+        checkPersistentLoginCookie( pwmRequest );
+
+        final ConfigManagerLoginAction processAction = readProcessAction( pwmRequest );
+        if ( processAction != null )
+        {
+            switch ( processAction )
+            {
+                case login:
+                    processLoginRequest( pwmRequest );
+                    break;
+
+                default:
+                    JavaHelper.unhandledSwitchStatement( processAction );
+
+            }
+            return;
+        }
+
+
+        final ConfigManagerBean configManagerBean = pwmRequest.getPwmApplication().getSessionStateService().getBean( pwmRequest, ConfigManagerBean.class );
+        if ( configManagerBean.isPasswordVerified() )
+        {
+            forwardToNextUrl( pwmRequest );
+            return;
+
+        }
+        forwardToJsp( pwmRequest );
+    }
+
+    protected void processLoginRequest( final PwmRequest pwmRequest )
+            throws PwmUnrecoverableException, IOException, ServletException
+    {
+        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
+        final ConfigurationReader runningConfigReader = ContextManager.getContextManager( pwmRequest.getHttpServletRequest().getSession() ).getConfigReader();
+        final StoredConfigurationImpl storedConfig = runningConfigReader.getStoredConfiguration();
+
+        final String password = pwmRequest.readParameterAsString( "password" );
+        if ( !StringUtil.isEmpty( password ) )
+        {
+            if ( storedConfig.verifyPassword( password, pwmRequest.getConfig() ) )
+            {
+                LOGGER.trace( pwmRequest, () -> "valid configuration password accepted" );
+                updateLoginHistory( pwmRequest, pwmRequest.getUserInfoIfLoggedIn(), true );
+                processLoginSuccess( pwmRequest, true );
+                return;
+            }
+            else
+            {
+                LOGGER.trace( pwmRequest, () -> "configuration password is not correct" );
+                pwmApplication.getIntruderManager().convenience().markAddressAndSession( pwmRequest.getPwmSession() );
+                pwmApplication.getIntruderManager().mark( RecordType.USERNAME, PwmConstants.CONFIGMANAGER_INTRUDER_USERNAME, pwmRequest.getSessionLabel() );
+                final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_PASSWORD_ONLY_BAD );
+                updateLoginHistory( pwmRequest, pwmRequest.getUserInfoIfLoggedIn(), false );
+                setLastError( pwmRequest, errorInformation );
+                forwardToJsp( pwmRequest );
+                return;
+            }
+        }
+    }
+
+
+    @Override
+    protected ConfigManagerLoginAction readProcessAction( final PwmRequest request )
+            throws PwmUnrecoverableException
+    {
+        try
+        {
+            return ConfigManagerLoginAction.valueOf( request.readParameterAsString( PwmConstants.PARAM_ACTION_REQUEST ) );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            return null;
+        }
+    }
+
+
+    private static void forwardToJsp( final PwmRequest pwmRequest )
+            throws ServletException, PwmUnrecoverableException, IOException
+    {
+        final int persistentSeconds = figureMaxLoginSeconds( pwmRequest );
+        final String time = TimeDuration.of( persistentSeconds, TimeDuration.Unit.SECONDS ).asLongString( pwmRequest.getLocale() );
+
+        final ConfigLoginHistory configLoginHistory = readConfigLoginHistory( pwmRequest );
+
+        pwmRequest.setAttribute( PwmRequestAttribute.ConfigLoginHistory, configLoginHistory );
+        pwmRequest.setAttribute( PwmRequestAttribute.ConfigPasswordRememberTime, time );
+        pwmRequest.forwardToJsp( JspUrl.CONFIG_MANAGER_LOGIN );
+    }
+
+
+    private static ConfigLoginHistory readConfigLoginHistory( final PwmRequest pwmRequest )
+    {
+        final ConfigLoginHistory configLoginHistory = pwmRequest.getPwmApplication().readAppAttribute( PwmApplication.AppAttribute.CONFIG_LOGIN_HISTORY, ConfigLoginHistory.class );
+        return configLoginHistory == null
+                ? new ConfigLoginHistory()
+                : configLoginHistory;
+    }
+
+    private static void updateLoginHistory( final PwmRequest pwmRequest, final UserIdentity userIdentity, final boolean successful )
+    {
+        final ConfigLoginHistory configLoginHistory = readConfigLoginHistory( pwmRequest );
+        final ConfigLoginEvent event = new ConfigLoginEvent(
+                userIdentity == null ? "n/a" : userIdentity.toDisplayString(),
+                Instant.now(),
+                pwmRequest.getPwmSession().getSessionStateBean().getSrcAddress()
+        );
+        final int maxEvents = Integer.parseInt( pwmRequest.getPwmApplication().getConfig().readAppProperty( AppProperty.CONFIG_HISTORY_MAX_ITEMS ) );
+        configLoginHistory.addEvent( event, maxEvents, successful );
+        pwmRequest.getPwmApplication().writeAppAttribute( PwmApplication.AppAttribute.CONFIG_LOGIN_HISTORY, configLoginHistory );
+    }
+
+    @Value
+    public static class ConfigLoginHistory implements Serializable
+    {
+        private List<ConfigLoginEvent> successEvents = new ArrayList<>();
+        private List<ConfigLoginEvent> failedEvents = new ArrayList<>();
+
+        void addEvent( final ConfigLoginEvent event, final int maxEvents, final boolean successful )
+        {
+            final List<ConfigLoginEvent> events = successful ? successEvents : failedEvents;
+            events.add( event );
+            if ( maxEvents > 0 )
+            {
+                while ( events.size() > maxEvents )
+                {
+                    events.remove( 0 );
+                }
+            }
+        }
+
+        public List<ConfigLoginEvent> successEvents( )
+        {
+            return Collections.unmodifiableList( successEvents );
+        }
+
+        public List<ConfigLoginEvent> failedEvents( )
+        {
+            return Collections.unmodifiableList( failedEvents );
+        }
+    }
+
+    @Value
+    public static class ConfigLoginEvent implements Serializable
+    {
+        private final String userIdentity;
+        private final Instant date;
+        private final String networkAddress;
+    }
+
+    private static ProcessStatus processLoginSuccess( final PwmRequest pwmRequest, final boolean persistentLoginEnabled )
+            throws PwmUnrecoverableException, IOException
+    {
+        final ConfigManagerBean configManagerBean = pwmRequest.getPwmApplication().getSessionStateService().getBean( pwmRequest, ConfigManagerBean.class );
+        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
+        final PwmSession pwmSession = pwmRequest.getPwmSession();
+
+        configManagerBean.setPasswordVerified( true );
+        pwmApplication.getIntruderManager().convenience().clearAddressAndSession( pwmSession );
+        pwmApplication.getIntruderManager().clear( RecordType.USERNAME, PwmConstants.CONFIGMANAGER_INTRUDER_USERNAME );
+        pwmRequest.getPwmSession().getSessionStateBean().setSessionIdRecycleNeeded( true );
+        if ( persistentLoginEnabled && "on".equals( pwmRequest.readParameterAsString( "remember" ) ) )
+        {
+            writePersistentLoginCookie( pwmRequest );
+        }
+
+        if ( configManagerBean.getPrePasswordEntryUrl() != null )
+        {
+            final String originalUrl = configManagerBean.getPrePasswordEntryUrl();
+            configManagerBean.setPrePasswordEntryUrl( null );
+            pwmRequest.getPwmResponse().sendRedirect( originalUrl );
+            return ProcessStatus.Halt;
+        }
+
+        pwmRequest.sendRedirect( pwmRequest.getURLwithQueryString() );
+        return ProcessStatus.Continue;
+    }
+
+    private static void forwardToNextUrl( final PwmRequest pwmRequest )
+            throws IOException, PwmUnrecoverableException
+    {
+        final ConfigManagerBean configManagerBean = pwmRequest.getPwmApplication().getSessionStateService().getBean( pwmRequest, ConfigManagerBean.class );
+
+        if ( configManagerBean.getPrePasswordEntryUrl() != null )
+        {
+            final String originalUrl = configManagerBean.getPrePasswordEntryUrl();
+            configManagerBean.setPrePasswordEntryUrl( null );
+            pwmRequest.getPwmResponse().sendRedirect( originalUrl );
+            return;
+        }
+
+        pwmRequest.sendRedirect( PwmServletDefinition.ConfigManager );
+    }
+
+
+    public static void writePersistentLoginCookie( final PwmRequest pwmRequest )
+            throws PwmUnrecoverableException
+    {
+        final int persistentSeconds = figureMaxLoginSeconds( pwmRequest );
+
+        if ( persistentSeconds > 0 )
+        {
+            final TimeDuration persistenceDuration = TimeDuration.of( persistentSeconds, TimeDuration.Unit.SECONDS );
+            final Instant expirationDate = persistenceDuration.incrementFromInstant( Instant.now() );
+            final StoredConfigurationImpl storedConfig = pwmRequest.getConfig().getStoredConfiguration();
+            final String persistentLoginValue = makePersistentLoginPassword( pwmRequest, storedConfig );
+            final PersistentLoginInfo persistentLoginInfo = new PersistentLoginInfo( expirationDate, persistentLoginValue );
+            final String cookieValue = pwmRequest.getPwmApplication().getSecureService().encryptObjectToString( persistentLoginInfo );
+            pwmRequest.getPwmResponse().writeCookie(
+                    COOKIE_NAME,
+                    cookieValue,
+                    persistentSeconds,
+                    COOKIE_PATH
+            );
+            LOGGER.debug( pwmRequest, () -> "set persistent config login cookie (expires "
+                    + JavaHelper.toIsoDate( expirationDate )
+                    + ")"
+            );
+        }
+    }
+
+    private static void checkPersistentLoginCookie(
+            final PwmRequest pwmRequest
+    )
+            throws PwmUnrecoverableException
+    {
+        if ( !persistentLoginEnabled( pwmRequest ) )
+        {
+            return;
+        }
+
+        final ConfigurationReader runningConfigReader = ContextManager.getContextManager( pwmRequest.getHttpServletRequest().getSession() ).getConfigReader();
+        final StoredConfigurationImpl storedConfig = runningConfigReader.getStoredConfiguration();
+
+        try
+        {
+            final String cookieValue = pwmRequest.readCookie( COOKIE_NAME );
+            if ( !StringUtil.isEmpty( cookieValue ) )
+            {
+                final PersistentLoginInfo persistentLoginInfo = pwmRequest.getPwmApplication().getSecureService().decryptObject( cookieValue, PersistentLoginInfo.class );
+                if ( persistentLoginInfo != null )
+                {
+                    if ( persistentLoginInfo.getExpireDate().isAfter( Instant.now() ) )
+                    {
+                        final String persistentLoginPassword = makePersistentLoginPassword( pwmRequest, storedConfig );
+                        if ( StringUtil.nullSafeEquals( persistentLoginPassword, persistentLoginInfo.getPassword() ) )
+                        {
+                            LOGGER.debug( pwmRequest, () -> "accepting persistent config login from cookie (expires "
+                                    + JavaHelper.toIsoDate( persistentLoginInfo.getExpireDate() )
+                                    + ")"
+                            );
+
+                            final ConfigManagerBean configManagerBean = pwmRequest.getPwmApplication().getSessionStateService().getBean( pwmRequest, ConfigManagerBean.class );
+                            configManagerBean.setPasswordVerified( true );
+                        }
+                    }
+
+                    pwmRequest.getPwmResponse().removeCookie( COOKIE_NAME, COOKIE_PATH );
+                    LOGGER.debug( pwmRequest, () -> "removing non-working persistent config login cookie" );
+                }
+            }
+        }
+        catch ( Exception e )
+        {
+            LOGGER.error( pwmRequest, "error examining persistent config login cookie: " + e.getMessage() );
+        }
+    }
+
+
+    @Value
+    private static class PersistentLoginInfo implements Serializable
+    {
+        @SerializedName( "e" )
+        private Instant expireDate;
+
+        @SerializedName( "p" )
+        private String password;
+    }
+
+    public static int figureMaxLoginSeconds( final PwmRequest pwmRequest )
+    {
+        return JavaHelper.silentParseInt(
+                pwmRequest.getConfig().readAppProperty( AppProperty.CONFIG_MAX_PERSISTENT_LOGIN_SECONDS ),
+                (int) TimeDuration.HOUR.as( TimeDuration.Unit.SECONDS )
+        );
+    }
+
+
+    private static String makePersistentLoginPassword(
+            final PwmRequest pwmRequest,
+            final StoredConfiguration storedConfig
+    )
+            throws PwmUnrecoverableException
+    {
+        final int hashChars = 32;
+        String hashValue = storedConfig.readConfigProperty( ConfigurationProperty.PASSWORD_HASH );
+
+        if ( PwmApplicationMode.RUNNING == pwmRequest.getPwmApplication().getApplicationMode() )
+        {
+            final PwmSession pwmSession = pwmRequest.getPwmSession();
+            hashValue += pwmSession.getUserInfo().getUserIdentity().toDelimitedKey();
+        }
+
+        return StringUtil.truncate( SecureEngine.hash( hashValue, PwmHashAlgorithm.SHA512 ), hashChars );
+    }
+
+
+    private static boolean persistentLoginEnabled(
+            final PwmRequest pwmRequest
+    )
+    {
+        if ( pwmRequest.getConfig().isDefaultValue( PwmSetting.PWM_SECURITY_KEY ) )
+        {
+            LOGGER.debug( pwmRequest, () -> "security not available, persistent login not possible." );
+            return false;
+        }
+
+        return true;
+    }
+}

+ 16 - 0
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerServlet.java

@@ -39,11 +39,13 @@ import password.pwm.http.HttpContentType;
 import password.pwm.http.HttpHeader;
 import password.pwm.http.HttpHeader;
 import password.pwm.http.HttpMethod;
 import password.pwm.http.HttpMethod;
 import password.pwm.http.JspUrl;
 import password.pwm.http.JspUrl;
+import password.pwm.http.ProcessStatus;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmRequestAttribute;
 import password.pwm.http.PwmRequestAttribute;
 import password.pwm.http.PwmResponse;
 import password.pwm.http.PwmResponse;
 import password.pwm.http.PwmSession;
 import password.pwm.http.PwmSession;
 import password.pwm.http.bean.ConfigManagerBean;
 import password.pwm.http.bean.ConfigManagerBean;
+import password.pwm.http.filter.ConfigAccessFilter;
 import password.pwm.http.servlet.AbstractPwmServlet;
 import password.pwm.http.servlet.AbstractPwmServlet;
 import password.pwm.http.servlet.PwmServletDefinition;
 import password.pwm.http.servlet.PwmServletDefinition;
 import password.pwm.http.servlet.configguide.ConfigGuideUtils;
 import password.pwm.http.servlet.configguide.ConfigGuideUtils;
@@ -121,9 +123,23 @@ public class ConfigManagerServlet extends AbstractPwmServlet
         }
         }
     }
     }
 
 
+    public static void verifyConfigAccess( final PwmRequest pwmRequest )
+            throws ServletException, PwmUnrecoverableException, IOException
+    {
+        final ConfigManagerBean configManagerBean = pwmRequest.getPwmApplication().getSessionStateService().getBean( pwmRequest, ConfigManagerBean.class );
+        final ProcessStatus processStatus = ConfigAccessFilter.checkAuthentication( pwmRequest, configManagerBean );
+        if ( processStatus != ProcessStatus.Continue )
+        {
+            final String msg = "config access authentication not yet completed";
+            throw PwmUnrecoverableException.newException( PwmError.ERROR_SERVICE_NOT_AVAILABLE, msg );
+        }
+    }
+
     protected void processAction( final PwmRequest pwmRequest )
     protected void processAction( final PwmRequest pwmRequest )
             throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
             throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
     {
     {
+        verifyConfigAccess( pwmRequest );
+
         final ConfigManagerAction processAction = readProcessAction( pwmRequest );
         final ConfigManagerAction processAction = readProcessAction( pwmRequest );
         if ( processAction != null )
         if ( processAction != null )
         {
         {

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerWordlistServlet.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.http.servlet.configmanager;
 package password.pwm.http.servlet.configmanager;
 
 
-import com.novell.ldapchai.exception.ChaiUnavailableException;
 import lombok.Builder;
 import lombok.Builder;
 import lombok.Value;
 import lombok.Value;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
@@ -102,8 +101,9 @@ public class ConfigManagerWordlistServlet extends AbstractPwmServlet
     }
     }
 
 
     protected void processAction( final PwmRequest pwmRequest )
     protected void processAction( final PwmRequest pwmRequest )
-            throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
+            throws ServletException, IOException, PwmUnrecoverableException
     {
     {
+        ConfigManagerServlet.verifyConfigAccess( pwmRequest );
 
 
         final ConfigManagerAction processAction = readProcessAction( pwmRequest );
         final ConfigManagerAction processAction = readProcessAction( pwmRequest );
         if ( processAction != null )
         if ( processAction != null )

+ 6 - 3
webapp/src/main/webapp/WEB-INF/jsp/configmanager-login.jsp

@@ -24,6 +24,8 @@
 <%@ page import="password.pwm.util.i18n.LocaleHelper" %>
 <%@ page import="password.pwm.util.i18n.LocaleHelper" %>
 <%@ page import="password.pwm.util.java.JavaHelper" %>
 <%@ page import="password.pwm.util.java.JavaHelper" %>
 <%@ page import="password.pwm.http.PwmRequestAttribute" %>
 <%@ page import="password.pwm.http.PwmRequestAttribute" %>
+<%@ page import="password.pwm.http.servlet.configmanager.ConfigManagerServlet" %>
+<%@ page import="password.pwm.http.servlet.configmanager.ConfigManagerLoginServlet" %>
 
 
 <!DOCTYPE html>
 <!DOCTYPE html>
 
 
@@ -66,11 +68,12 @@
                     <pwm:if test="<%=PwmIfTest.showIcons%>"><span class="btn-icon pwm-icon pwm-icon-sign-in"></span></pwm:if>
                     <pwm:if test="<%=PwmIfTest.showIcons%>"><span class="btn-icon pwm-icon pwm-icon-sign-in"></span></pwm:if>
                     <pwm:display key="Button_Login"/>
                     <pwm:display key="Button_Login"/>
                 </button>
                 </button>
+                <input type="hidden" name="processAction" value="<%=ConfigManagerLoginServlet.ConfigManagerLoginAction.login%>"/>
                 <%@ include file="/WEB-INF/jsp/fragment/cancel-button.jsp" %>
                 <%@ include file="/WEB-INF/jsp/fragment/cancel-button.jsp" %>
                 <input type="hidden" id="pwmFormID" name="pwmFormID" value="<pwm:FormID/>" autofocus/>
                 <input type="hidden" id="pwmFormID" name="pwmFormID" value="<pwm:FormID/>" autofocus/>
             </div>
             </div>
         </form>
         </form>
-        <% final ConfigAccessFilter.ConfigLoginHistory configLoginHistory = (ConfigAccessFilter.ConfigLoginHistory)JspUtility.getAttribute(pageContext, PwmRequestAttribute.ConfigLoginHistory); %>
+        <% final ConfigManagerLoginServlet.ConfigLoginHistory configLoginHistory = (ConfigManagerLoginServlet.ConfigLoginHistory)JspUtility.getAttribute(pageContext, PwmRequestAttribute.ConfigLoginHistory); %>
         <% if (configLoginHistory != null && !configLoginHistory.successEvents().isEmpty()) { %>
         <% if (configLoginHistory != null && !configLoginHistory.successEvents().isEmpty()) { %>
         <h2 style="margin-top: 15px;">Previous Authentications</h2>
         <h2 style="margin-top: 15px;">Previous Authentications</h2>
         <table>
         <table>
@@ -79,7 +82,7 @@
                 <td class="title">Timestamp</td>
                 <td class="title">Timestamp</td>
                 <td class="title">Network Address</td>
                 <td class="title">Network Address</td>
             </tr>
             </tr>
-            <% for (final ConfigAccessFilter.ConfigLoginEvent event : configLoginHistory.successEvents()) { %>
+            <% for (final ConfigManagerLoginServlet.ConfigLoginEvent event : configLoginHistory.successEvents()) { %>
             <tr>
             <tr>
                 <td><%=event.getUserIdentity()%></td>
                 <td><%=event.getUserIdentity()%></td>
                 <td><span  class="timestamp"><%=JavaHelper.toIsoDate(event.getDate())%></span></td>
                 <td><span  class="timestamp"><%=JavaHelper.toIsoDate(event.getDate())%></span></td>
@@ -97,7 +100,7 @@
                 <td class="title">Timestamp</td>
                 <td class="title">Timestamp</td>
                 <td class="title">Network Address</td>
                 <td class="title">Network Address</td>
             </tr>
             </tr>
-            <% for (final ConfigAccessFilter.ConfigLoginEvent event : configLoginHistory.failedEvents()) { %>
+            <% for (final ConfigManagerLoginServlet.ConfigLoginEvent event : configLoginHistory.failedEvents()) { %>
             <tr>
             <tr>
                 <td><%=event.getUserIdentity()%></td>
                 <td><%=event.getUserIdentity()%></td>
                 <td><span  class="timestamp"><%=JavaHelper.toIsoDate(event.getDate())%></span></td>
                 <td><span  class="timestamp"><%=JavaHelper.toIsoDate(event.getDate())%></span></td>