Ver Fonte

improve idle timeout handling and logging

Jason Rivard há 8 anos atrás
pai
commit
cc68d83aed

+ 86 - 19
src/main/java/password/pwm/http/IdleTimeoutCalculator.java

@@ -22,65 +22,132 @@
 
 package password.pwm.http;
 
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 import password.pwm.AppProperty;
 import password.pwm.Permission;
 import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
+import password.pwm.PwmConstants;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.profile.HelpdeskProfile;
+import password.pwm.config.profile.ProfileType;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.servlet.PwmServletDefinition;
+import password.pwm.ldap.UserInfo;
+import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
+import java.util.Collections;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
 
 public class IdleTimeoutCalculator {
     private static final PwmLogger LOGGER = PwmLogger.forClass(IdleTimeoutCalculator.class);
 
-    public static TimeDuration figureMaxIdleTimeout(final PwmApplication pwmApplication, final PwmSession pwmSession) throws PwmUnrecoverableException
+    public static MaxIdleTimeoutResult figureMaxSessionTimeout(final PwmApplication pwmApplication, final PwmSession pwmSession)
+            throws PwmUnrecoverableException
     {
         final Configuration configuration = pwmApplication.getConfig();
-        long idleSeconds = configuration.readSettingAsLong(PwmSetting.IDLE_TIMEOUT_SECONDS);
+        final SortedSet<MaxIdleTimeoutResult> results = new TreeSet<>();
+        {
+            final long idleSetting = configuration.readSettingAsLong(PwmSetting.IDLE_TIMEOUT_SECONDS);
+            results.add(new MaxIdleTimeoutResult(
+                    MaxIdleTimeoutResult.reasonFor(PwmSetting.IDLE_TIMEOUT_SECONDS, null),
+                    new TimeDuration(idleSetting, TimeUnit.SECONDS)));
+        }
 
         if (!pwmSession.isAuthenticated()) {
+            if (pwmApplication.getApplicationMode() == PwmApplicationMode.NEW) {
+                final long configGuideIdleTimeout = Long.parseLong(configuration.readAppProperty(AppProperty.CONFIG_GUIDE_IDLE_TIMEOUT));
+                results.add(new MaxIdleTimeoutResult(
+                        "Configuration Guide Idle Timeout",
+                        new TimeDuration(configGuideIdleTimeout, TimeUnit.SECONDS)));
+            }
+
             if (configuration.readSettingAsBoolean(PwmSetting.PEOPLE_SEARCH_ENABLE_PUBLIC)) {
                 final long peopleSearchIdleTimeout = configuration.readSettingAsLong(PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS);
-                idleSeconds = Math.max(idleSeconds, peopleSearchIdleTimeout);
+                if (peopleSearchIdleTimeout > 0) {
+                    results.add(new MaxIdleTimeoutResult(
+                            MaxIdleTimeoutResult.reasonFor(PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS, null),
+                            new TimeDuration(peopleSearchIdleTimeout, TimeUnit.SECONDS)));
+                }
             }
 
-            return TimeDuration.fromCurrent(idleSeconds);
+        } else {
+            final UserInfo userInfo= pwmSession.getUserInfo();
+            final boolean userIsAdmin = pwmSession.getSessionManager().checkPermission(pwmApplication, Permission.PWMADMIN);
+            final Set<MaxIdleTimeoutResult> loggedInResults = figureMaxAuthUserTimeout(configuration, userInfo, userIsAdmin);
+            results.addAll(loggedInResults);
+        }
+
+        return results.last();
+    }
+
+    private static Set<MaxIdleTimeoutResult> figureMaxAuthUserTimeout(
+            final Configuration configuration,
+            final UserInfo userInfo,
+            final boolean userIsAdmin
+    )
+            throws PwmUnrecoverableException
+    {
+        final Set<MaxIdleTimeoutResult> results = new TreeSet<>();
+        {
+            final long idleSetting = configuration.readSettingAsLong(PwmSetting.IDLE_TIMEOUT_SECONDS);
+            results.add(new MaxIdleTimeoutResult(
+                    MaxIdleTimeoutResult.reasonFor(PwmSetting.IDLE_TIMEOUT_SECONDS, null),
+                    new TimeDuration(idleSetting, TimeUnit.SECONDS)));
         }
 
         if (configuration.readSettingAsBoolean(PwmSetting.HELPDESK_ENABLE)) {
-            final HelpdeskProfile helpdeskProfile = pwmSession.getSessionManager().getHelpdeskProfile(pwmApplication);
-            if (helpdeskProfile != null) {
+            final String helpdeskProfileID = userInfo.getProfileIDs().get(ProfileType.Helpdesk);
+            if (!StringUtil.isEmpty(helpdeskProfileID)) {
+                final HelpdeskProfile helpdeskProfile = configuration.getHelpdeskProfiles().get(helpdeskProfileID);
                 final long helpdeskIdleTimeout = helpdeskProfile.readSettingAsLong(PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS);
-                idleSeconds = Math.max(idleSeconds, helpdeskIdleTimeout);
+                results.add(new MaxIdleTimeoutResult(
+                        MaxIdleTimeoutResult.reasonFor(PwmSetting.HELPDESK_IDLE_TIMEOUT_SECONDS, helpdeskProfileID),
+                        new TimeDuration(helpdeskIdleTimeout, TimeUnit.SECONDS)));
             }
         }
 
         if (configuration.readSettingAsBoolean(PwmSetting.PEOPLE_SEARCH_ENABLE)) {
             final long peopleSearchIdleTimeout = configuration.readSettingAsLong(PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS);
-            idleSeconds = Math.max(idleSeconds, peopleSearchIdleTimeout);
+            if (peopleSearchIdleTimeout > 0) {
+                results.add(new MaxIdleTimeoutResult(
+                        MaxIdleTimeoutResult.reasonFor(PwmSetting.PEOPLE_SEARCH_IDLE_TIMEOUT_SECONDS, null),
+                        new TimeDuration(peopleSearchIdleTimeout, TimeUnit.SECONDS)));
+            }
         }
 
-        if (pwmApplication.getApplicationMode() == PwmApplicationMode.NEW) {
-            final long configGuideIdleTimeout = Long.parseLong(configuration.readAppProperty(AppProperty.CONFIG_GUIDE_IDLE_TIMEOUT));
-            idleSeconds = Math.max(idleSeconds, configGuideIdleTimeout);
+        if (userIsAdmin) {
+            final long configEditorIdleTimeout = Long.parseLong(configuration.readAppProperty(AppProperty.CONFIG_EDITOR_IDLE_TIMEOUT));
+            results.add(new MaxIdleTimeoutResult(
+                    "Config Editor Idle Timeout",
+                    new TimeDuration(configEditorIdleTimeout, TimeUnit.SECONDS)));
         }
 
-        try {
-            if (pwmSession.getSessionManager().checkPermission(pwmApplication, Permission.PWMADMIN)) {
-                final long configEditorIdleTimeout = Long.parseLong(configuration.readAppProperty(AppProperty.CONFIG_EDITOR_IDLE_TIMEOUT));
-                idleSeconds = Math.max(idleSeconds, configEditorIdleTimeout);
-            }
-        } catch (PwmUnrecoverableException e) {
-            LOGGER.error(pwmSession,"error while figuring max idle timeout for session: " + e.getMessage());
+        return Collections.unmodifiableSet(results);
+    }
+
+    @Getter
+    @AllArgsConstructor
+    static class MaxIdleTimeoutResult implements Comparable<MaxIdleTimeoutResult> {
+        private final String reason;
+        private final TimeDuration idleTimeout;
+
+        @Override
+        public int compareTo(MaxIdleTimeoutResult o)
+        {
+            return this.idleTimeout.compareTo(o.getIdleTimeout());
         }
 
-        return new TimeDuration(idleSeconds, TimeUnit.SECONDS);
+        static String reasonFor(final PwmSetting pwmSetting, final String profileID) {
+            return "Setting " + pwmSetting.toMenuLocationDebug(profileID, PwmConstants.DEFAULT_LOCALE);
+        }
     }
 
     public static TimeDuration idleTimeoutForRequest(final PwmRequest pwmRequest) throws PwmUnrecoverableException

+ 17 - 3
src/main/java/password/pwm/http/PwmSessionWrapper.java

@@ -27,12 +27,13 @@ import password.pwm.PwmConstants;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.java.TimeDuration;
+import password.pwm.util.logging.PwmLogger;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
 public class PwmSessionWrapper {
+    private static final PwmLogger LOGGER = PwmLogger.forClass(PwmSessionWrapper.class);
 
     private transient PwmSession pwmSession;
 
@@ -49,8 +50,7 @@ public class PwmSessionWrapper {
     {
         httpSession.setAttribute(PwmConstants.SESSION_ATTR_PWM_SESSION, pwmSession);
 
-        final TimeDuration maxIdleTime = IdleTimeoutCalculator.figureMaxIdleTimeout(pwmApplication, pwmSession);
-        httpSession.setMaxInactiveInterval((int) maxIdleTime.getTotalSeconds());
+        setHttpSessionIdleTimeout(pwmApplication, pwmSession, httpSession);
     }
 
 
@@ -67,4 +67,18 @@ public class PwmSessionWrapper {
     public static PwmSession readPwmSession(final HttpServletRequest httpRequest) throws PwmUnrecoverableException {
         return readPwmSession(httpRequest.getSession());
     }
+
+    public static void setHttpSessionIdleTimeout(
+            final PwmApplication pwmApplication,
+            final PwmSession pwmSession,
+            final HttpSession httpSession
+    ) throws PwmUnrecoverableException
+    {
+        final IdleTimeoutCalculator.MaxIdleTimeoutResult result = IdleTimeoutCalculator.figureMaxSessionTimeout(pwmApplication, pwmSession);
+        if (httpSession.getMaxInactiveInterval() != result.getIdleTimeout().getTotalSeconds()) {
+            httpSession.setMaxInactiveInterval((int) result.getIdleTimeout().getTotalSeconds());
+            LOGGER.trace(pwmSession, "setting java servlet session timeout to " + result.getIdleTimeout().asCompactString()
+                    + " due to " + result.getReason());
+        }
+    }
 }

+ 4 - 7
src/main/java/password/pwm/http/filter/RequestInitializationFilter.java

@@ -468,11 +468,8 @@ public class RequestInitializationFilter implements Filter {
             initializeLocaleAndTheme(pwmRequest);
         }
 
-        // set idle timeout (may get overridden by module-specific values elsewhere
-        if (!pwmURL.isResourceURL() && !pwmURL.isCommandServletURL() && !pwmURL.isWebServiceURL()){
-            final TimeDuration maxIdleTimeout = IdleTimeoutCalculator.figureMaxIdleTimeout(pwmRequest.getPwmApplication(), pwmRequest.getPwmSession());
-            pwmRequest.getHttpServletRequest().getSession().setMaxInactiveInterval((int) maxIdleTimeout.getTotalSeconds());
-        }
+        // set idle timeout
+        PwmSessionWrapper.setHttpSessionIdleTimeout(pwmRequest.getPwmApplication(), pwmRequest.getPwmSession(), pwmRequest.getHttpServletRequest().getSession());
     }
 
     private static void initializeLocaleAndTheme(
@@ -665,9 +662,9 @@ public class RequestInitializationFilter implements Filter {
         final TimeDuration maxDurationForRequest = IdleTimeoutCalculator.idleTimeoutForRequest(pwmRequest);
         final TimeDuration currentDuration = TimeDuration.fromCurrent(pwmRequest.getHttpServletRequest().getSession().getLastAccessedTime());
         if (currentDuration.isLongerThan(maxDurationForRequest)) {
-            LOGGER.debug("closing session due to idle time, max for request is " + maxDurationForRequest.asCompactString() + ", session idle time is " + currentDuration.asCompactString());
+            LOGGER.debug("unauthenticated session due to idle time, max for request is " + maxDurationForRequest.asCompactString()
+                    + ", session idle time is " + currentDuration.asCompactString());
             pwmRequest.getPwmSession().unauthenticateUser(pwmRequest);
-            throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_USERAUTHENTICATED,"idle timeout exceeded"));
         }
     }
 

+ 7 - 4
src/main/java/password/pwm/ws/server/RestServerHelper.java

@@ -34,6 +34,7 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.http.HttpHeader;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmSession;
 import password.pwm.http.filter.AuthenticationFilter;
@@ -46,7 +47,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Response;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
 import java.util.Locale;
@@ -54,9 +54,12 @@ import java.util.Locale;
 public abstract class RestServerHelper {
     private static final PwmLogger LOGGER = PwmLogger.forClass(RestServerHelper.class);
 
-    public static javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
-        final URI uri = javax.ws.rs.core.UriBuilder.fromUri("../reference/rest.jsp?forwardedFromRestServer=true").build();
-        return javax.ws.rs.core.Response.temporaryRedirect(uri).build();
+    public static javax.ws.rs.core.Response handleHtmlRequest() throws URISyntaxException {
+        final String msg = "This REST service requires an appropriate "
+                + HttpHeader.Accept.getHttpName() + " header to be set.  This request used an html "
+                + HttpHeader.Accept.getHttpName() + " header, which is not supported.  See documentation at \"/public/reference/\".";
+        final String content = "<html><body>" + msg + "</body></html>";
+        return javax.ws.rs.core.Response.status(Response.Status.NOT_ACCEPTABLE).entity(content).build();
     }
 
     public static RestRequestBean initializeRestRequest(

+ 2 - 3
src/main/java/password/pwm/ws/server/StandaloneRestRequestBean.java

@@ -27,12 +27,11 @@ import lombok.Getter;
 import password.pwm.PwmApplication;
 import password.pwm.config.option.WebServiceUsage;
 
-import java.util.HashSet;
 import java.util.Set;
 
 @Getter
 @Builder
 public class StandaloneRestRequestBean {
-    private Set<WebServiceUsage> authorizedUsages = new HashSet<>();
-    private PwmApplication pwmApplication;
+    private final Set<WebServiceUsage> authorizedUsages;
+    private final PwmApplication pwmApplication;
 }

+ 1 - 1
src/main/java/password/pwm/ws/server/rest/RestAppDataServer.java

@@ -106,7 +106,7 @@ public class RestAppDataServer extends AbstractRestServer {
     @GET
     @Produces(MediaType.TEXT_HTML)
     public javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
-        return RestServerHelper.doHtmlRedirect();
+        return RestServerHelper.handleHtmlRequest();
     }
 
     @GET

+ 1 - 1
src/main/java/password/pwm/ws/server/rest/RestChallengesServer.java

@@ -144,7 +144,7 @@ public class RestChallengesServer extends AbstractRestServer {
     @GET
     @Produces(MediaType.TEXT_HTML)
     public javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
-        return RestServerHelper.doHtmlRedirect();
+        return RestServerHelper.handleHtmlRequest();
     }
 
     @GET

+ 1 - 1
src/main/java/password/pwm/ws/server/rest/RestStatusServer.java

@@ -57,7 +57,7 @@ public class RestStatusServer extends AbstractRestServer {
     @GET
     @Produces(MediaType.TEXT_HTML)
     public javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
-        return RestServerHelper.doHtmlRedirect();
+        return RestServerHelper.handleHtmlRequest();
     }
 
     @GET

+ 1 - 1
src/main/java/password/pwm/ws/server/rest/RestVerifyOtpServer.java

@@ -61,7 +61,7 @@ public class RestVerifyOtpServer extends AbstractRestServer {
     @GET
     @Produces(MediaType.TEXT_HTML)
     public Response doHtmlRedirect() throws URISyntaxException {
-        return RestServerHelper.doHtmlRedirect();
+        return RestServerHelper.handleHtmlRequest();
     }
 
     @POST

+ 1 - 1
src/main/java/password/pwm/ws/server/rest/RestVerifyResponsesServer.java

@@ -90,7 +90,7 @@ public class RestVerifyResponsesServer extends AbstractRestServer {
     @GET
     @Produces(MediaType.TEXT_HTML)
     public Response doHtmlRedirect() throws URISyntaxException {
-        return RestServerHelper.doHtmlRedirect();
+        return RestServerHelper.handleHtmlRequest();
     }
 
     @POST