Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions jspwiki-main/src/main/java/org/apache/wiki/WikiSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ public String antiCsrfToken() {
return antiCsrfToken;
}

/**
* Regenerates the anti-CSRF token. Called when the session's privilege level changes (i.e. at login), so that
* a token observed before authentication cannot be replayed against the authenticated session.
*/
public void regenerateAntiCsrfToken() {
antiCsrfToken = UUID.randomUUID().toString();
}

/** {@inheritDoc} */
@Override
public Locale getLocale() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import java.util.Properties;
import java.util.Set;
import org.apache.wiki.WikiContext;
import org.apache.wiki.WikiSession;
import org.apache.wiki.auth.user.UserProfile;


Expand Down Expand Up @@ -178,6 +179,7 @@ public boolean login( final HttpServletRequest request ) throws WikiSecurityExce

// If the container logged the user in successfully, tell the Session (and add all the Principals)
if (!principals.isEmpty()) {
rotateSessionAfterAuthentication( request, session );
fireEvent( WikiSecurityEvent.LOGIN_AUTHENTICATED, getLoginPrincipal( principals ), session, request );
for( final Principal principal : principals ) {
fireEvent( WikiSecurityEvent.PRINCIPAL_ADD, principal, session, request );
Expand Down Expand Up @@ -269,6 +271,7 @@ public boolean login( final Session session, final HttpServletRequest request, f
// Execute the user's specified login module
final Set< Principal > principals = doJAASLogin( m_loginModuleClass, handler, m_loginModuleOptions );
if(!principals.isEmpty()) {
rotateSessionAfterAuthentication( request, session );
fireEvent(WikiSecurityEvent.LOGIN_AUTHENTICATED, getLoginPrincipal( principals ), session, request );
for ( final Principal principal : principals ) {
fireEvent( WikiSecurityEvent.PRINCIPAL_ADD, principal, session, request );
Expand All @@ -282,6 +285,34 @@ public boolean login( final Session session, final HttpServletRequest request, f
return false;
}

/**
* Session-fixation defense: the pre-authentication HTTP session id and anti-CSRF token must not survive the
* upgrade to an authenticated session. Rotates the servlet session id, re-keys the {@link SessionMonitor} entry
* so the wiki session attaches to the new id, and regenerates the wiki session's anti-CSRF token so a token
* observed before login cannot be replayed against the authenticated session.
*
* @param request the servlet request, may be <code>null</code> (e.g. embedded use); nothing to rotate then
* @param session the wiki session being upgraded
*/
private void rotateSessionAfterAuthentication( final HttpServletRequest request, final Session session ) {
if( request != null ) {
final HttpSession httpSession = request.getSession( false );
if( httpSession != null ) {
final SessionMonitor monitor = SessionMonitor.getInstance( m_engine );
monitor.remove( httpSession );
try {
request.changeSessionId();
} catch( final IllegalStateException e ) {
LOG.debug( "Unable to rotate the http session id: {}", e.getMessage() );
}
monitor.register( httpSession, session );
}
}
if( session instanceof WikiSession ) {
( ( WikiSession )session ).regenerateAntiCsrfToken();
}
}

/**
* This method builds a database of login names that are being attempted, and will try to delay if there are too many requests coming
* in for the same username.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,23 @@ public final void remove( final HttpSession session ) {
}
}

/**
* (Re-)associates a wiki session with the user's current HTTP session id. Needed after the HTTP session id has
* been rotated at authentication time (session-fixation defense), so that the upgraded privileges attach to the
* new session id instead of the pre-login one.
*
* @param session the user's HTTP session, carrying its current id
* @param wikiSession the wiki session to register under that id
*/
public final void register( final HttpSession session, final Session wikiSession ) {
if( session == null || wikiSession == null ) {
throw new IllegalArgumentException( "Session cannot be null." );
}
synchronized( m_sessions ) {
m_sessions.put( session.getId(), wikiSession );
}
}

/**
* Returns the current number of active wiki sessions.
* @return the number of sessions
Expand Down
Loading