/* * 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.filter; import password.pwm.AppProperty; import password.pwm.PwmApplication; import password.pwm.PwmApplicationMode; import password.pwm.PwmConstants; import password.pwm.bean.LocalSessionStateBean; import password.pwm.config.Configuration; import password.pwm.config.PwmSetting; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmException; import password.pwm.error.PwmUnrecoverableException; import password.pwm.http.ContextManager; import password.pwm.http.HttpHeader; import password.pwm.http.IdleTimeoutCalculator; import password.pwm.http.JspUrl; import password.pwm.http.PwmRequest; import password.pwm.http.PwmRequestAttribute; import password.pwm.http.PwmResponse; import password.pwm.http.PwmSession; import password.pwm.http.PwmSessionWrapper; import password.pwm.http.PwmURL; import password.pwm.svc.stats.Statistic; import password.pwm.svc.stats.StatisticsManager; import password.pwm.util.IPMatcher; import password.pwm.util.LocaleHelper; import password.pwm.util.java.StringUtil; import password.pwm.util.java.TimeDuration; import password.pwm.util.logging.PwmLogger; import password.pwm.util.macro.MacroMachine; import password.pwm.util.secure.PwmRandom; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.Instant; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; public class RequestInitializationFilter implements Filter { private static final PwmLogger LOGGER = PwmLogger.forClass(RequestInitializationFilter.class); @Override public void init(final FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } public void doFilter( final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest req = (HttpServletRequest)servletRequest; final HttpServletResponse resp = (HttpServletResponse)servletResponse; final PwmApplicationMode mode = PwmApplicationMode.determineMode(req); final PwmURL pwmURL = new PwmURL(req); PwmApplication testPwmApplicationLoad = null; try { testPwmApplicationLoad = ContextManager.getPwmApplication(req); } catch (PwmException e) {} if (testPwmApplicationLoad == null && pwmURL.isResourceURL()) { filterChain.doFilter(req, resp); } else { if (mode == PwmApplicationMode.ERROR) { try { final ContextManager contextManager = ContextManager.getContextManager(req.getServletContext()); if (contextManager != null) { final ErrorInformation startupError = contextManager.getStartupErrorInformation(); servletRequest.setAttribute(PwmRequestAttribute.PwmErrorInfo.toString(), startupError); } } catch (Exception e) { if (pwmURL.isResourceURL()) { filterChain.doFilter(servletRequest, servletResponse); return; } LOGGER.error("error while trying to detect application status: " + e.getMessage()); } LOGGER.error("unable to satisfy incoming request, application is not available"); resp.setStatus(500); final String url = JspUrl.APP_UNAVAILABLE.getPath(); servletRequest.getServletContext().getRequestDispatcher(url).forward(servletRequest, servletResponse); } else { initializeServletRequest(req, resp, filterChain); } } } private void initializeServletRequest( final HttpServletRequest req, final HttpServletResponse resp, final FilterChain filterChain ) throws IOException, ServletException { try { checkAndInitSessionState(req); PwmRequest.forRequest(req,resp); } catch (Throwable e) { LOGGER.error("can't load application: " + e.getMessage(),e); if (!(new PwmURL(req).isResourceURL())) { ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_APP_UNAVAILABLE); try { final ContextManager contextManager = ContextManager.getContextManager(req.getServletContext()); if (contextManager != null) { errorInformation = contextManager.getStartupErrorInformation(); } } catch (Throwable e2) { e2.getMessage(); } req.setAttribute(PwmRequestAttribute.PwmErrorInfo.toString(),errorInformation); final String url = JspUrl.APP_UNAVAILABLE.getPath(); req.getServletContext().getRequestDispatcher(url).forward(req, resp); } return; } try { final PwmRequest pwmRequest = PwmRequest.forRequest(req,resp); checkIfSessionRecycleNeeded(pwmRequest); handleRequestInitialization(pwmRequest); addPwmResponseHeaders(pwmRequest); checkIdleTimeout(pwmRequest); try { handleRequestSecurityChecks(pwmRequest); } catch (PwmUnrecoverableException e) { LOGGER.error(pwmRequest, e.getErrorInformation()); pwmRequest.respondWithError(e.getErrorInformation()); if (PwmError.ERROR_INTRUDER_SESSION != e.getError()) { pwmRequest.invalidateSession(); } return; } } catch (Throwable e) { final String logMsg = "can't init request: " + e.getMessage(); if (e instanceof PwmException && ((PwmException) e).getError() != PwmError.ERROR_UNKNOWN) { LOGGER.error(logMsg); } else { LOGGER.error(logMsg,e); } if (!(new PwmURL(req).isResourceURL())) { ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_APP_UNAVAILABLE); try { final ContextManager contextManager = ContextManager.getContextManager(req.getServletContext()); if (contextManager != null) { errorInformation = contextManager.getStartupErrorInformation(); } } catch (Throwable e2) { e2.getMessage(); } req.setAttribute(PwmRequestAttribute.PwmErrorInfo.toString(),errorInformation); final String url = JspUrl.APP_UNAVAILABLE.getPath(); req.getServletContext().getRequestDispatcher(url).forward(req, resp); } return; } filterChain.doFilter(req, resp); } private void checkAndInitSessionState(final HttpServletRequest request) throws PwmUnrecoverableException { final ContextManager contextManager = ContextManager.getContextManager(request.getSession()); { // destroy any outdated sessions final HttpSession httpSession = request.getSession(false); if (httpSession != null) { final String sessionContextInitGUID = (String) httpSession.getAttribute(PwmConstants.SESSION_ATTR_CONTEXT_GUID); if (sessionContextInitGUID == null || !sessionContextInitGUID.equals(contextManager.getInstanceGuid())) { LOGGER.debug("invalidating http session created with non-current servlet context"); httpSession.invalidate(); } } } { // handle pwmSession init and assignment. final HttpSession httpSession = request.getSession(); if (httpSession.getAttribute(PwmConstants.SESSION_ATTR_PWM_SESSION) == null) { final PwmApplication pwmApplication = contextManager.getPwmApplication(); final PwmSession pwmSession = PwmSession.createPwmSession(pwmApplication); PwmSessionWrapper.sessionMerge(pwmApplication, pwmSession, httpSession); } } } private void checkIfSessionRecycleNeeded(final PwmRequest pwmRequest) throws IOException, ServletException { if (!pwmRequest.getPwmSession().getSessionStateBean().isSessionIdRecycleNeeded()) { return; } final boolean recycleEnabled = Boolean.parseBoolean( pwmRequest.getConfig().readAppProperty(AppProperty.HTTP_SESSION_RECYCLE_AT_AUTH)); if (!recycleEnabled) { return; } LOGGER.debug(pwmRequest,"forcing new http session due to authentication"); final HttpServletRequest req = pwmRequest.getHttpServletRequest(); // read the old session data final HttpSession oldSession = req.getSession(true); final int oldMaxInactiveInterval = oldSession.getMaxInactiveInterval(); final Map<String,Object> sessionAttributes = new HashMap<>(); final Enumeration oldSessionAttrNames = oldSession.getAttributeNames(); while (oldSessionAttrNames.hasMoreElements()) { final String attrName = (String)oldSessionAttrNames.nextElement(); sessionAttributes.put(attrName, oldSession.getAttribute(attrName)); } for (final String attrName : sessionAttributes.keySet()) { oldSession.removeAttribute(attrName); } //invalidate the old session oldSession.invalidate(); // make a new session final HttpSession newSession = req.getSession(true); // write back all the session data for (final String attrName : sessionAttributes.keySet()) { newSession.setAttribute(attrName, sessionAttributes.get(attrName)); } newSession.setMaxInactiveInterval(oldMaxInactiveInterval); pwmRequest.getPwmSession().getSessionStateBean().setSessionIdRecycleNeeded(false); } public static void addPwmResponseHeaders( final PwmRequest pwmRequest ) throws PwmUnrecoverableException { if (pwmRequest == null) { return; } final PwmApplication pwmApplication = pwmRequest.getPwmApplication(); final PwmSession pwmSession = pwmRequest.getPwmSession(); final Configuration config = pwmApplication.getConfig(); final PwmResponse resp = pwmRequest.getPwmResponse(); if (resp.isCommitted()) { return; } final String serverHeader = config.readAppProperty(AppProperty.HTTP_HEADER_SERVER); final boolean includeXInstance = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XINSTANCE)); final boolean includeXSessionID = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XSESSIONID)); final boolean includeXVersion = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XVERSION)); final boolean includeXContentTypeOptions = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XCONTENTTYPEOPTIONS)); final boolean includeXXSSProtection = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XXSSPROTECTION)); final boolean sendNoise = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XNOISE)); if (sendNoise) { final int noiseLength = Integer.parseInt(config.readAppProperty(AppProperty.HTTP_HEADER_NOISE_LENGTH)); resp.setHeader( HttpHeader.XNoise, PwmRandom.getInstance().alphaNumericString(PwmRandom.getInstance().nextInt(noiseLength)+11) ); } if (includeXVersion) { resp.setHeader(HttpHeader.XVersion, PwmConstants.SERVLET_VERSION); } if (includeXContentTypeOptions) { resp.setHeader(HttpHeader.XContentTypeOptions, "nosniff"); } if (includeXXSSProtection) { resp.setHeader(HttpHeader.XXSSProtection, "1"); } if (includeXInstance) { resp.setHeader(HttpHeader.XInstance, String.valueOf(pwmApplication.getInstanceID())); } if (includeXSessionID && pwmSession != null) { resp.setHeader(HttpHeader.XSessionID, pwmSession.getSessionStateBean().getSessionID()); } if (serverHeader != null && !serverHeader.isEmpty()) { final String value = MacroMachine.forNonUserSpecific(pwmApplication, null).expandMacros(serverHeader); resp.setHeader(HttpHeader.Server, value); } if (pwmRequest.getURL().isResourceURL()) { return; } // ----- non-resource urls only for the following operations ----- final boolean includeXFrameDeny = config.readSettingAsBoolean(PwmSetting.SECURITY_PREVENT_FRAMING); final boolean includeXAmb = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_XAMB)); final boolean includeContentLanguage = Boolean.parseBoolean(config.readAppProperty(AppProperty.HTTP_HEADER_SEND_CONTENT_LANGUAGE)); if (includeXFrameDeny) { resp.setHeader(HttpHeader.XFrameOptions, "DENY"); } if (includeXAmb) { resp.setHeader(HttpHeader.XAmb, PwmConstants.X_AMB_HEADER[PwmRandom.getInstance().nextInt(PwmConstants.X_AMB_HEADER.length)]); } if (includeContentLanguage) { resp.setHeader(HttpHeader.Content_Language, pwmRequest.getLocale().toLanguageTag()); } resp.setHeader(HttpHeader.Cache_Control, "no-cache, no-store, must-revalidate, proxy-revalidate"); if (pwmSession != null) { final String contentPolicy; if (pwmRequest.getURL().isConfigGuideURL() || pwmRequest.getURL().isConfigManagerURL()) { contentPolicy = config.readAppProperty(AppProperty.SECURITY_HTTP_CONFIG_CSP_HEADER); } else { contentPolicy = config.readSettingAsString(PwmSetting.SECURITY_CSP_HEADER); } if (contentPolicy != null && !contentPolicy.isEmpty()) { final String nonce = pwmRequest.getCspNonce(); final String expandedPolicy = contentPolicy.replace("%NONCE%", nonce); resp.setHeader(HttpHeader.ContentSecurityPolicy, expandedPolicy); } } } public static String readUserHostname(final PwmRequest pwmRequest) throws PwmUnrecoverableException { final Configuration config = pwmRequest.getConfig(); if (config != null && !config.readSettingAsBoolean(PwmSetting.REVERSE_DNS_ENABLE)) { return ""; } final String userIPAddress = readUserIPAddress(pwmRequest); try { return InetAddress.getByName(userIPAddress).getCanonicalHostName(); } catch (UnknownHostException e) { LOGGER.trace(pwmRequest, "unknown host while trying to compute hostname for src request: " + e.getMessage()); } return ""; } /** * Returns the IP address of the user. If there is an X-Forwarded-For header in the request, that address will * be used. Otherwise, the source address of the request is used. * * @return String containing the textual representation of the source IP address, or null if the request is invalid. */ public static String readUserIPAddress(final PwmRequest pwmRequest) throws PwmUnrecoverableException { final Configuration config = pwmRequest.getConfig(); final boolean useXForwardedFor = config != null && config.readSettingAsBoolean(PwmSetting.USE_X_FORWARDED_FOR_HEADER); String userIP = ""; if (useXForwardedFor) { try { userIP = pwmRequest.readHeaderValueAsString(PwmConstants.HTTP_HEADER_X_FORWARDED_FOR); if (userIP != null) { final int commaIndex = userIP.indexOf(','); if (commaIndex > -1) { userIP = userIP.substring(0, commaIndex); } } } catch (Exception e) { //ip address not in header (no X-Forwarded-For) } } if (userIP == null || userIP.length() < 1) { userIP = pwmRequest.getHttpServletRequest().getRemoteAddr(); } return userIP == null ? "" : userIP; } public static void handleRequestInitialization( final PwmRequest pwmRequest ) throws PwmUnrecoverableException { final LocalSessionStateBean ssBean = pwmRequest.getPwmSession().getSessionStateBean(); final PwmURL pwmURL = pwmRequest.getURL(); // mark if first request if (ssBean.getSessionCreationTime() == null) { ssBean.setSessionCreationTime(Instant.now()); ssBean.setSessionLastAccessedTime(Instant.now()); } // mark session ip address if (ssBean.getSrcAddress() == null) { ssBean.setSrcAddress(readUserIPAddress(pwmRequest)); } // mark the user's hostname in the session bean if (ssBean.getSrcHostname() == null) { ssBean.setSrcHostname(readUserHostname(pwmRequest)); } // update the privateUrlAccessed flag if (pwmURL.isPrivateUrl()) { ssBean.setPrivateUrlAccessed(true); } // initialize the session's locale if (ssBean.getLocale() == null) { 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()); } } private static void initializeLocaleAndTheme( final PwmRequest pwmRequest ) throws PwmUnrecoverableException { final String localeCookieName = pwmRequest.getConfig().readAppProperty(AppProperty.HTTP_COOKIE_LOCALE_NAME); final String localeCookie = pwmRequest.readCookie(localeCookieName); if (localeCookieName.length() > 0 && localeCookie != null) { LOGGER.debug(pwmRequest, "detected locale cookie in request, setting locale to " + localeCookie); pwmRequest.getPwmSession().setLocale(pwmRequest.getPwmApplication(), localeCookie); } else { final List<Locale> knownLocales = pwmRequest.getConfig().getKnownLocales(); final Locale userLocale = LocaleHelper.localeResolver(pwmRequest.getHttpServletRequest().getLocale(), knownLocales); pwmRequest.getPwmSession().getSessionStateBean().setLocale(userLocale == null ? PwmConstants.DEFAULT_LOCALE : userLocale); LOGGER.trace(pwmRequest, "user locale set to '" + pwmRequest.getLocale() + "'"); } final String themeCookieName = pwmRequest.getConfig().readAppProperty(AppProperty.HTTP_COOKIE_THEME_NAME); final String themeCookie = pwmRequest.readCookie(themeCookieName); if (localeCookieName.length() > 0 && themeCookie != null && themeCookie.length() > 0) { if (pwmRequest.getPwmApplication().getResourceServletService().checkIfThemeExists(pwmRequest, themeCookie)) { LOGGER.debug(pwmRequest, "detected theme cookie in request, setting theme to " + themeCookie); pwmRequest.getPwmSession().getSessionStateBean().setTheme(themeCookie); } } } public static void handleRequestSecurityChecks( final PwmRequest pwmRequest ) throws PwmUnrecoverableException { final LocalSessionStateBean ssBean = pwmRequest.getPwmSession().getSessionStateBean(); // check the user's IP address if (!pwmRequest.getConfig().readSettingAsBoolean(PwmSetting.MULTI_IP_SESSION_ALLOWED)) { final String remoteAddress = readUserIPAddress(pwmRequest); if (!ssBean.getSrcAddress().equals(remoteAddress)) { final String errorMsg = "current network address '" + remoteAddress + "' has changed from original network address '" + ssBean.getSrcAddress() + "'"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,errorMsg); throw new PwmUnrecoverableException(errorInformation); } } // check total time. { if (ssBean.getSessionCreationTime() != null) { final Long maxSessionSeconds = pwmRequest.getConfig().readSettingAsLong(PwmSetting.SESSION_MAX_SECONDS); final TimeDuration sessionAge = TimeDuration.fromCurrent(ssBean.getSessionCreationTime()); if (sessionAge.getTotalSeconds() > maxSessionSeconds) { final String errorMsg = "session age (" + sessionAge.asCompactString() + ") is longer than maximum permitted age"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,errorMsg); throw new PwmUnrecoverableException(errorInformation); } } } // check headers { final List<String> requiredHeaders = pwmRequest.getConfig().readSettingAsStringArray(PwmSetting.REQUIRED_HEADERS); if (requiredHeaders != null && !requiredHeaders.isEmpty()) { final Map<String, String> configuredValues = StringUtil.convertStringListToNameValuePair(requiredHeaders, "="); for (final String key : configuredValues.keySet()) { if (key != null && key.length() > 0) { final String requiredValue = configuredValues.get(key); if (requiredValue != null && requiredValue.length() > 0) { final String value = pwmRequest.readHeaderValueAsString(key); if (value == null || value.length() < 1) { final String errorMsg = "request is missing required value for header '" + key + "'"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,errorMsg); throw new PwmUnrecoverableException(errorInformation); } else { if (!requiredValue.equals(value)) { final String errorMsg = "request has incorrect required value for header '" + key + "'"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,errorMsg); throw new PwmUnrecoverableException(errorInformation); } } } } } } } // check permitted source IP address { final List<String> requiredHeaders = pwmRequest.getConfig().readSettingAsStringArray(PwmSetting.IP_PERMITTED_RANGE); if (requiredHeaders != null && !requiredHeaders.isEmpty()) { boolean match = false; final String requestAddress = pwmRequest.getHttpServletRequest().getRemoteAddr(); for (int i = 0; i < requiredHeaders.size() && !match; i++) { final String ipMatchString = requiredHeaders.get(i); try { final IPMatcher ipMatcher = new IPMatcher(ipMatchString); try { if (ipMatcher.match(requestAddress)) { match = true; } } catch (IPMatcher.IPMatcherException e) { LOGGER.error("error while attempting to match permitted address range '" + ipMatchString + "', error: " + e); } } catch (IPMatcher.IPMatcherException e) { LOGGER.error("error parsing permitted address range '" + ipMatchString + "', error: " + e); } } if (!match) { final String errorMsg = "request network address '" + requestAddress + "' does not match any configured permitted source address"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,errorMsg); throw new PwmUnrecoverableException(errorInformation); } } } // csrf cross-site request forgery checks final boolean performCsrfHeaderChecks = Boolean.parseBoolean(pwmRequest.getConfig().readAppProperty(AppProperty.SECURITY_HTTP_PERFORM_CSRF_HEADER_CHECKS)); if ( performCsrfHeaderChecks && !pwmRequest.getMethod().isIdempotent() && !pwmRequest.getURL().isWebServiceURL() ) { final String originValue = pwmRequest.readHeaderValueAsString(HttpHeader.Origin); final String referrerValue = pwmRequest.readHeaderValueAsString(HttpHeader.Referer); final String siteUrl = pwmRequest.getPwmApplication().getConfig().readSettingAsString(PwmSetting.PWM_SITE_URL); final String targetValue = pwmRequest.getHttpServletRequest().getRequestURL().toString(); if (StringUtil.isEmpty(targetValue)) { final String msg = "malformed request instance, missing target uri value"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION, msg); LOGGER.debug(pwmRequest, errorInformation.toDebugStr() + " [" + makeHeaderDebugStr(pwmRequest) + "]"); throw new PwmUnrecoverableException(errorInformation); } final boolean originHeaderEvaluated; if (!StringUtil.isEmpty(originValue)) { if (!PwmURL.compareUriBase(originValue, targetValue)) { final String msg = "cross-origin request not permitted: origin header does not match incoming target url" + " [" + makeHeaderDebugStr(pwmRequest) + "]"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION, msg); LOGGER.debug(pwmRequest, errorInformation.toDebugStr()); throw new PwmUnrecoverableException(errorInformation); } originHeaderEvaluated = true; } else { originHeaderEvaluated = false; } final boolean referrerHeaderEvaluated; if (!StringUtil.isEmpty(referrerValue)) { if (!PwmURL.compareUriBase(referrerValue, targetValue) && !PwmURL.compareUriBase(referrerValue, siteUrl)) { final String msg = "cross-origin request not permitted: referrer header does not match incoming target url" + " [" + makeHeaderDebugStr(pwmRequest) + "]"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION, msg); LOGGER.debug(pwmRequest, errorInformation.toDebugStr()); throw new PwmUnrecoverableException(errorInformation); } referrerHeaderEvaluated = true; } else { referrerHeaderEvaluated = false; } if (!referrerHeaderEvaluated && !originHeaderEvaluated && !PwmURL.compareUriBase(originValue, siteUrl)) { final String msg = "neither referer nor origin header request are present on non-idempotent request"; final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION, msg); LOGGER.debug(pwmRequest, errorInformation.toDebugStr() + " [" + makeHeaderDebugStr(pwmRequest) + "]"); throw new PwmUnrecoverableException(errorInformation); } } // check trial if (PwmConstants.TRIAL_MODE) { final String currentAuthString = pwmRequest.getPwmApplication().getStatisticsManager().getStatBundleForKey(StatisticsManager.KEY_CURRENT).getStatistic(Statistic.AUTHENTICATIONS); if (new BigInteger(currentAuthString).compareTo(BigInteger.valueOf(PwmConstants.TRIAL_MAX_AUTHENTICATIONS)) > 0) { throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_TRIAL_VIOLATION,"maximum usage per server startup exceeded")); } final String totalAuthString = pwmRequest.getPwmApplication().getStatisticsManager().getStatBundleForKey(StatisticsManager.KEY_CUMULATIVE).getStatistic(Statistic.AUTHENTICATIONS); if (new BigInteger(totalAuthString).compareTo(BigInteger.valueOf(PwmConstants.TRIAL_MAX_TOTAL_AUTH)) > 0) { throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_TRIAL_VIOLATION,"maximum usage for this server has been exceeded")); } } // check intruder pwmRequest.getPwmApplication().getIntruderManager().convenience().checkAddressAndSession(pwmRequest.getPwmSession()); } private void checkIdleTimeout(final PwmRequest pwmRequest) throws PwmUnrecoverableException { 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()); pwmRequest.getPwmSession().unauthenticateUser(pwmRequest); throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_USERAUTHENTICATED,"idle timeout exceeded")); } } private static String makeHeaderDebugStr(final PwmRequest pwmRequest) { final Map<String,String> values = new LinkedHashMap<>(); for (final HttpHeader header : new HttpHeader[]{HttpHeader.Referer, HttpHeader.Origin}) { values.put(header.getHttpName(), pwmRequest.readHeaderValueAsString(header)); } values.put("target", pwmRequest.getHttpServletRequest().getRequestURL().toString()); values.put("siteUrl", pwmRequest.getPwmApplication().getConfig().readSettingAsString(PwmSetting.PWM_SITE_URL)); return StringUtil.mapToString(values); } }