123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- /*
- * Password Management Servlets (PWM)
- * http://www.pwm-project.org
- *
- * Copyright (c) 2006-2009 Novell, Inc.
- * Copyright (c) 2009-2020 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;
- import lombok.Value;
- import org.apache.commons.fileupload.FileItemIterator;
- import org.apache.commons.fileupload.FileItemStream;
- import org.apache.commons.fileupload.servlet.ServletFileUpload;
- import org.apache.commons.io.IOUtils;
- import password.pwm.AppProperty;
- import password.pwm.PwmApplication;
- import password.pwm.PwmApplicationMode;
- import password.pwm.PwmConstants;
- import password.pwm.PwmDomain;
- import password.pwm.bean.DomainID;
- import password.pwm.bean.LocalSessionStateBean;
- import password.pwm.bean.LoginInfoBean;
- import password.pwm.bean.SessionLabel;
- import password.pwm.bean.UserIdentity;
- import password.pwm.config.DomainConfig;
- import password.pwm.config.PwmSetting;
- import password.pwm.config.profile.AccountInformationProfile;
- import password.pwm.config.profile.ChangePasswordProfile;
- import password.pwm.config.profile.DeleteAccountProfile;
- import password.pwm.config.profile.HelpdeskProfile;
- import password.pwm.config.profile.PeopleSearchProfile;
- import password.pwm.config.profile.Profile;
- import password.pwm.config.profile.ProfileDefinition;
- import password.pwm.config.profile.SetupOtpProfile;
- import password.pwm.config.profile.UpdateProfileProfile;
- import password.pwm.config.value.data.FormConfiguration;
- import password.pwm.error.ErrorInformation;
- import password.pwm.error.PwmError;
- import password.pwm.error.PwmUnrecoverableException;
- import password.pwm.http.bean.ImmutableByteArray;
- import password.pwm.http.servlet.AbstractPwmServlet;
- import password.pwm.http.servlet.PwmRequestID;
- import password.pwm.http.servlet.PwmServletDefinition;
- import password.pwm.ldap.UserInfo;
- import password.pwm.util.Validator;
- import password.pwm.util.java.LazySupplier;
- import password.pwm.util.java.StringUtil;
- import password.pwm.util.java.TimeDuration;
- import password.pwm.util.logging.PwmLogLevel;
- import password.pwm.util.logging.PwmLogger;
- import password.pwm.util.secure.PwmSecurityKey;
- import password.pwm.ws.server.RestResultBean;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.Serializable;
- import java.time.Instant;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.EnumSet;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.Optional;
- import java.util.Set;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- import java.util.function.Supplier;
- public class PwmRequest extends PwmHttpRequestWrapper
- {
- private static final PwmLogger LOGGER = PwmLogger.forClass( PwmRequest.class );
- private final PwmResponse pwmResponse;
- private final PwmURL pwmURL;
- private final PwmRequestID pwmRequestID;
- private final transient PwmApplication pwmApplication;
- private final transient Supplier<SessionLabel> sessionLabelLazySupplier = new LazySupplier<>( this::makeSessionLabel );
- private final Set<PwmRequestFlag> flags = EnumSet.noneOf( PwmRequestFlag.class );
- private final Instant requestStartTime = Instant.now();
- private final DomainID domainID;
- private final Lock cspCreationLock = new ReentrantLock();
- private static final Lock CREATE_LOCK = new ReentrantLock();
- public static PwmRequest forRequest(
- final HttpServletRequest request,
- final HttpServletResponse response
- )
- throws PwmUnrecoverableException
- {
- CREATE_LOCK.lock();
- try
- {
- PwmRequest pwmRequest = ( PwmRequest ) request.getAttribute( PwmRequestAttribute.PwmRequest.toString() );
- if ( pwmRequest == null )
- {
- final PwmApplication pwmApplication = ContextManager.getPwmApplication( request );
- pwmRequest = new PwmRequest( request, response, pwmApplication );
- request.setAttribute( PwmRequestAttribute.PwmRequest.toString(), pwmRequest );
- }
- return pwmRequest;
- }
- finally
- {
- CREATE_LOCK.unlock();
- }
- }
- private PwmRequest(
- final HttpServletRequest httpServletRequest,
- final HttpServletResponse httpServletResponse,
- final PwmApplication pwmApplication
- )
- throws PwmUnrecoverableException
- {
- super( httpServletRequest, pwmApplication.getConfig() );
- this.pwmRequestID = PwmRequestID.next();
- this.pwmResponse = new PwmResponse( httpServletResponse, this, pwmApplication.getConfig() );
- this.pwmApplication = pwmApplication;
- this.pwmURL = PwmURL.create( this.getHttpServletRequest() );
- this.domainID = PwmHttpRequestWrapper.readDomainIdFromRequest( httpServletRequest );
- }
- public PwmDomain getPwmDomain( )
- {
- return pwmApplication.domains().get( getDomainID() );
- }
- public PwmSession getPwmSession( )
- {
- return getPwmSession( this.getPwmDomain() );
- }
- public PwmSession getPwmSession( final PwmDomain pwmDomain )
- {
- return PwmSessionFactory.readPwmSession( this.getHttpServletRequest().getSession(), pwmDomain );
- }
- public SessionLabel getLabel( )
- {
- return sessionLabelLazySupplier.get();
- }
- private SessionLabel makeSessionLabel( )
- {
- return getPwmSession().getLabel().toBuilder()
- .requestID( pwmRequestID.toString() )
- .build();
- }
- public PwmResponse getPwmResponse( )
- {
- return pwmResponse;
- }
- public Locale getLocale( )
- {
- if ( isFlag( PwmRequestFlag.INCLUDE_CONFIG_CSS ) )
- {
- return PwmConstants.DEFAULT_LOCALE;
- }
- if ( !getURL().isLocalizable() )
- {
- return PwmConstants.DEFAULT_LOCALE;
- }
- return getPwmSession().getSessionStateBean().getLocale();
- }
- public void forwardToJsp( final JspUrl jspURL )
- throws ServletException, IOException, PwmUnrecoverableException
- {
- this.getPwmResponse().forwardToJsp( jspURL );
- }
- public void respondWithError( final ErrorInformation errorInformation )
- throws IOException, ServletException, PwmUnrecoverableException
- {
- respondWithError( errorInformation, true );
- }
- public void respondWithError(
- final ErrorInformation errorInformation,
- final boolean forceLogout
- )
- throws IOException, ServletException, PwmUnrecoverableException
- {
- if ( forceLogout )
- {
- getPwmResponse().respondWithError( errorInformation, PwmResponse.Flag.ForceLogout );
- }
- else
- {
- getPwmResponse().respondWithError( errorInformation );
- }
- }
- public void outputJsonResult( final RestResultBean restResultBean )
- throws IOException
- {
- this.getPwmResponse().outputJsonResult( restResultBean );
- }
- public ContextManager getContextManager( )
- throws PwmUnrecoverableException
- {
- return ContextManager.getContextManager( this );
- }
- public Optional<InputStream> readFileUploadStream( final String filePartName )
- throws IOException, ServletException, PwmUnrecoverableException
- {
- try
- {
- if ( ServletFileUpload.isMultipartContent( this.getHttpServletRequest() ) )
- {
- // Create a new file upload handler
- final ServletFileUpload upload = new ServletFileUpload();
- // Parse the request
- for ( final FileItemIterator iter = upload.getItemIterator( this.getHttpServletRequest() ); iter.hasNext(); )
- {
- final FileItemStream item = iter.next();
- if ( filePartName.equals( item.getFieldName() ) )
- {
- return Optional.of( item.openStream() );
- }
- }
- }
- }
- catch ( final Exception e )
- {
- LOGGER.error( () -> "error reading file upload: " + e.getMessage() );
- }
- return Optional.empty();
- }
- public Map<String, FileUploadItem> readFileUploads(
- final int maxFileSize,
- final int maxItems
- )
- throws PwmUnrecoverableException
- {
- final Map<String, FileUploadItem> returnObj = new LinkedHashMap<>();
- try
- {
- if ( ServletFileUpload.isMultipartContent( this.getHttpServletRequest() ) )
- {
- final ServletFileUpload upload = new ServletFileUpload();
- final FileItemIterator iter = upload.getItemIterator( this.getHttpServletRequest() );
- while ( iter.hasNext() && returnObj.size() < maxItems )
- {
- final FileItemStream item = iter.next();
- final InputStream inputStream = item.openStream();
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final long length = IOUtils.copyLarge( inputStream, baos, 0, maxFileSize + 1 );
- if ( length > maxFileSize )
- {
- final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, "upload file size limit exceeded" );
- LOGGER.error( this, errorInformation );
- respondWithError( errorInformation );
- return Collections.emptyMap();
- }
- final byte[] outputFile = baos.toByteArray();
- final FileUploadItem fileUploadItem = new FileUploadItem(
- item.getName(),
- item.getContentType(),
- ImmutableByteArray.of( outputFile )
- );
- returnObj.put( item.getFieldName(), fileUploadItem );
- }
- }
- }
- catch ( final Exception e )
- {
- LOGGER.error( () -> "error reading file upload: " + e.getMessage() );
- }
- return Collections.unmodifiableMap( returnObj );
- }
- @Value
- public static class FileUploadItem
- {
- private final String name;
- private final String type;
- private final ImmutableByteArray content;
- }
- public UserIdentity getUserInfoIfLoggedIn( )
- {
- return this.getPwmSession().isAuthenticated()
- ? this.getPwmSession().getUserInfo().getUserIdentity()
- : null;
- }
- public void validatePwmFormID( )
- throws PwmUnrecoverableException
- {
- Validator.validatePwmFormID( this );
- }
- public boolean convertURLtokenCommand(
- final PwmServletDefinition pwmServletDefinition,
- final AbstractPwmServlet.ProcessAction processAction
- )
- throws IOException, PwmUnrecoverableException
- {
- final String uri = getURLwithoutQueryString();
- if ( uri == null || uri.length() < 1 )
- {
- return false;
- }
- final String servletPath = this.getHttpServletRequest().getServletPath();
- if ( !uri.contains( servletPath ) )
- {
- LOGGER.error( () -> "unexpected uri handler, uri '" + uri + "' does not contain servlet path '" + servletPath + "'" );
- return false;
- }
- String aftPath = uri.substring( uri.indexOf( servletPath ) + servletPath.length() );
- if ( aftPath.startsWith( "/" ) )
- {
- aftPath = aftPath.substring( 1 );
- }
- if ( aftPath.contains( "?" ) )
- {
- aftPath = aftPath.substring( 0, aftPath.indexOf( "?" ) );
- }
- if ( aftPath.contains( "&" ) )
- {
- aftPath = aftPath.substring( 0, aftPath.indexOf( "?" ) );
- }
- if ( aftPath.length() <= 1 )
- {
- return false;
- }
- // note this value is still urlencoded - the servlet container does not decode path values.
- final String tokenValue = aftPath;
- final StringBuilder redirectURL = new StringBuilder();
- redirectURL.append( this.getHttpServletRequest().getContextPath() );
- redirectURL.append( pwmServletDefinition.servletUrl() );
- redirectURL.append( "?" );
- redirectURL.append( PwmConstants.PARAM_ACTION_REQUEST ).append( "=" ).append( processAction.toString() );
- redirectURL.append( "&" );
- redirectURL.append( PwmConstants.PARAM_TOKEN ).append( "=" ).append( tokenValue );
- LOGGER.debug( this, () -> "detected long servlet url, redirecting user to " + redirectURL );
- getPwmResponse().sendRedirect( redirectURL.toString() );
- return true;
- }
- public void setAttribute( final PwmRequestAttribute name, final Serializable value )
- {
- this.getHttpServletRequest().setAttribute( name.toString(), value );
- }
- public Serializable getAttribute( final PwmRequestAttribute name )
- {
- return ( Serializable ) this.getHttpServletRequest().getAttribute( name.toString() );
- }
- public PwmURL getURL( )
- {
- return pwmURL;
- }
- public void debugHttpRequestToLog( final String extraText, final Supplier<TimeDuration> timeDuration )
- throws PwmUnrecoverableException
- {
- if ( LOGGER.isEnabled( PwmLogLevel.TRACE ) )
- {
- final String moreExtraText = ( StringUtil.isEmpty( extraText ) ? "" : extraText + " " )
- + "request=" + this.getPwmRequestID() + ", domain=" + this.getDomainID().stringValue();
- final String debugTxt = debugHttpRequestToString( moreExtraText, false );
- LOGGER.trace( this.getLabel(), () -> debugTxt, timeDuration );
- }
- }
- public boolean isAuthenticated( )
- {
- return getPwmSession().isAuthenticated();
- }
- public boolean isForcedPageView( ) throws PwmUnrecoverableException
- {
- if ( !isAuthenticated() )
- {
- return false;
- }
- final PwmURL pwmURL = getURL();
- final UserInfo userInfoBean = getPwmSession().getUserInfo();
- if ( getPwmSession().getLoginInfoBean().isLoginFlag( LoginInfoBean.LoginFlag.forcePwChange ) && pwmURL.isChangePasswordURL() )
- {
- return true;
- }
- if ( userInfoBean.isRequiresNewPassword() && pwmURL.isChangePasswordURL() )
- {
- return true;
- }
- if ( userInfoBean.isRequiresResponseConfig() && pwmURL.matches( PwmServletDefinition.SetupResponses ) )
- {
- return true;
- }
- if ( userInfoBean.isRequiresOtpConfig() && pwmURL.matches( PwmServletDefinition.SetupOtp ) )
- {
- return true;
- }
- if ( userInfoBean.isRequiresUpdateProfile() && pwmURL.matches( PwmServletDefinition.UpdateProfile ) )
- {
- return true;
- }
- return false;
- }
- public void setFlag( final PwmRequestFlag flag, final boolean status )
- {
- if ( status )
- {
- flags.add( flag );
- }
- else
- {
- flags.remove( flag );
- }
- }
- public boolean isFlag( final PwmRequestFlag flag )
- {
- return flags.contains( flag );
- }
- public boolean hasForwardUrl( )
- {
- final LocalSessionStateBean ssBean = this.getPwmSession().getSessionStateBean();
- final String redirectURL = ssBean.getForwardURL();
- return StringUtil.notEmpty( redirectURL );
- }
- public String getForwardUrl( )
- {
- final LocalSessionStateBean ssBean = this.getPwmSession().getSessionStateBean();
- String redirectURL = ssBean.getForwardURL();
- if ( StringUtil.isEmpty( redirectURL ) )
- {
- redirectURL = this.getDomainConfig().readSettingAsString( PwmSetting.URL_FORWARD );
- }
- if ( StringUtil.isEmpty( redirectURL ) )
- {
- redirectURL = this.getBasePath();
- }
- if ( StringUtil.isEmpty( redirectURL ) )
- {
- redirectURL = "/";
- }
- return redirectURL;
- }
- public String getLogoutURL(
- )
- {
- final LocalSessionStateBean ssBean = this.getPwmSession().getSessionStateBean();
- return ssBean.getLogoutURL() == null ? pwmApplication.getConfig().readSettingAsString( PwmSetting.URL_LOGOUT ) : ssBean.getLogoutURL();
- }
- public String getCspNonce( )
- throws PwmUnrecoverableException
- {
- cspCreationLock.lock();
- try
- {
- if ( getAttribute( PwmRequestAttribute.CspNonce ) == null )
- {
- final int nonceLength = Integer.parseInt( getDomainConfig().readAppProperty( AppProperty.HTTP_HEADER_CSP_NONCE_BYTES ) );
- final byte[] cspNonce = getPwmDomain().getSecureService().pwmRandom().newBytes( nonceLength );
- final String cspString = StringUtil.base64Encode( cspNonce );
- setAttribute( PwmRequestAttribute.CspNonce, cspString );
- }
- return ( String ) getAttribute( PwmRequestAttribute.CspNonce );
- }
- finally
- {
- cspCreationLock.unlock();
- }
- }
- public <T extends Serializable> Optional<T> readEncryptedCookie( final String cookieName, final Class<T> returnClass )
- throws PwmUnrecoverableException
- {
- final Optional<String> strValue = this.readCookie( cookieName );
- if ( strValue.isEmpty() )
- {
- return Optional.empty();
- }
- final PwmSecurityKey pwmSecurityKey = getPwmSession().getSecurityKey( this );
- final T t = getPwmDomain().getSecureService().decryptObject( strValue.get(), pwmSecurityKey, returnClass );
- return Optional.of( t );
- }
- @Override
- public String toString( )
- {
- return this.getClass().getSimpleName() + " "
- + ( this.getLabel() == null ? "" : getLabel().toString() )
- + " " + getURLwithoutQueryString();
- }
- public void addFormInfoToRequestAttr(
- final PwmSetting formSetting,
- final boolean readOnly,
- final boolean showPasswordFields
- )
- {
- final ArrayList<FormConfiguration> formConfiguration = new ArrayList<>( this.getDomainConfig().readSettingAsForm( formSetting ) );
- addFormInfoToRequestAttr( formConfiguration, null, readOnly, showPasswordFields );
- }
- public void addFormInfoToRequestAttr(
- final List<FormConfiguration> formConfiguration,
- final Map<FormConfiguration, String> formDataMap,
- final boolean readOnly,
- final boolean showPasswordFields
- )
- {
- final LinkedHashMap<FormConfiguration, String> formDataMapValue = formDataMap == null
- ? new LinkedHashMap<>()
- : new LinkedHashMap<>( formDataMap );
- this.setAttribute( PwmRequestAttribute.FormConfiguration, new ArrayList<>( formConfiguration ) );
- this.setAttribute( PwmRequestAttribute.FormData, formDataMapValue );
- this.setAttribute( PwmRequestAttribute.FormReadOnly, readOnly );
- this.setAttribute( PwmRequestAttribute.FormShowPasswordFields, showPasswordFields );
- }
- public void invalidateSession( )
- throws PwmUnrecoverableException
- {
- this.getPwmSession().unauthenticateUser( this );
- this.getHttpServletRequest().getSession().invalidate();
- }
- public String getURLwithQueryString( ) throws PwmUnrecoverableException
- {
- return PwmURL.appendAndEncodeUrlParameters( getURLwithoutQueryString(), readParametersAsMap() );
- }
- public boolean endUserFunctionalityAvailable( )
- {
- final PwmApplicationMode mode = pwmApplication.getApplicationMode();
- if ( mode == PwmApplicationMode.NEW )
- {
- return false;
- }
- if ( PwmConstants.TRIAL_MODE )
- {
- return true;
- }
- if ( mode == PwmApplicationMode.RUNNING )
- {
- return true;
- }
- return false;
- }
- public String getContextPath( )
- {
- return this.getHttpServletRequest().getContextPath();
- }
- public String getBasePath( )
- {
- final String rawContextPath = this.getHttpServletRequest().getContextPath();
- if ( getAppConfig().isMultiDomain() )
- {
- return rawContextPath + "/" + this.getDomainID().stringValue();
- }
- return rawContextPath;
- }
- public PwmRequestContext getPwmRequestContext()
- {
- return new PwmRequestContext( pwmApplication, this.getDomainID(), this.getLabel(), this.getLocale(), pwmRequestID );
- }
- public String getPwmRequestID()
- {
- return pwmRequestID.toString();
- }
- public Instant getRequestStartTime()
- {
- return requestStartTime;
- }
- public DomainID getDomainID()
- {
- return domainID;
- }
- public DomainConfig getDomainConfig()
- {
- return getPwmDomain().getConfig();
- }
- public PwmApplication getPwmApplication()
- {
- return pwmApplication;
- }
- private Profile getProfile( final PwmDomain pwmDomain, final ProfileDefinition profileDefinition ) throws PwmUnrecoverableException
- {
- if ( profileDefinition.isAuthenticated() && !getPwmSession().isAuthenticated() )
- {
- throw new IllegalStateException( "can not read authenticated profile while session is unauthenticated" );
- }
- final String profileID = getPwmSession().getUserInfo().getProfileIDs().get( profileDefinition );
- if ( profileID != null )
- {
- return pwmDomain.getConfig().getProfileMap( profileDefinition ).get( profileID );
- }
- throw new PwmUnrecoverableException( PwmError.ERROR_NO_PROFILE_ASSIGNED );
- }
- public HelpdeskProfile getHelpdeskProfile() throws PwmUnrecoverableException
- {
- return ( HelpdeskProfile ) getProfile( getPwmDomain(), ProfileDefinition.Helpdesk );
- }
- public SetupOtpProfile getSetupOTPProfile() throws PwmUnrecoverableException
- {
- return ( SetupOtpProfile ) getProfile( getPwmDomain(), ProfileDefinition.SetupOTPProfile );
- }
- public UpdateProfileProfile getUpdateAttributeProfile() throws PwmUnrecoverableException
- {
- return ( UpdateProfileProfile ) getProfile( getPwmDomain(), ProfileDefinition.UpdateAttributes );
- }
- public PeopleSearchProfile getPeopleSearchProfile() throws PwmUnrecoverableException
- {
- return ( PeopleSearchProfile ) getProfile( getPwmDomain(), ProfileDefinition.PeopleSearch );
- }
- public DeleteAccountProfile getSelfDeleteProfile() throws PwmUnrecoverableException
- {
- return ( DeleteAccountProfile ) getProfile( getPwmDomain(), ProfileDefinition.DeleteAccount );
- }
- public ChangePasswordProfile getChangePasswordProfile() throws PwmUnrecoverableException
- {
- return ( ChangePasswordProfile ) getProfile( getPwmDomain(), ProfileDefinition.ChangePassword );
- }
- public AccountInformationProfile getAccountInfoProfile() throws PwmUnrecoverableException
- {
- return ( AccountInformationProfile ) getProfile( getPwmDomain(), ProfileDefinition.AccountInformation );
- }
- }
|