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
21 changes: 21 additions & 0 deletions jspwiki-api/src/main/java/org/apache/wiki/api/core/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,25 @@ public interface Session extends WikiEventListener {
*/
Subject getSubject();

/**
* Wrapper for {@link Subject#doAsPrivileged(Subject, PrivilegedAction, java.security.AccessControlContext)}
* that executes an action with the privileges possessed by a Session's Subject. The action executes with a <code>null</code>
* AccessControlContext, which has the effect of running it "cleanly" without the AccessControlContexts of the caller.
*
* @param session the wiki session
* @param action the privileged action
* @return the result of the privileged action; may be <code>null</code>
* @throws java.security.AccessControlException if the action is not permitted by the security policy
*/
static Object doPrivileged( final Session session, final PrivilegedAction<?> action ) throws AccessControlException {
return Subject.doAsPrivileged( session.getSubject(), action, null );
}

/**
* returns the remote address of the user login session, usually an ip address
* @since 3.0.0
* @return string
*/
String getRemoteAddress();

}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ public final class WikiSecurityEvent extends WikiEvent {

/** When a low disk space is encountered . */
public static final int LOW_STORAGE = 55;
/** Login audit alert, multiple concurrent logins from the different ip addresses . */
public static final int LOGIN_ALERT = 56;

/** The security logging service. */
private static final Logger LOG = LogManager.getLogger( "SecurityLog" );
Expand All @@ -123,7 +125,7 @@ public final class WikiSecurityEvent extends WikiEvent {

private final Object m_target;

private static final int[] ERROR_EVENTS = { LOGIN_FAILED };
private static final int[] ERROR_EVENTS = { LOGIN_FAILED, LOGIN_ALERT };

private static final int[] WARN_EVENTS = { LOGIN_ACCOUNT_EXPIRED, LOGIN_CREDENTIAL_EXPIRED };

Expand Down Expand Up @@ -249,6 +251,7 @@ public String getTypeDescription() {
case LOGIN_ACCOUNT_EXPIRED: return "login failed: expired account";
case LOGIN_CREDENTIAL_EXPIRED: return "login failed: credential expired";
case LOGIN_FAILED: return "login failed";
case LOGIN_ALERT: return "login alert";
case LOGOUT: return "user logged out";
case PRINCIPAL_ADD: return "new principal added";
case SESSION_EXPIRED: return "session expired";
Expand Down
9 changes: 7 additions & 2 deletions jspwiki-main/src/main/java/org/apache/wiki/WikiSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class WikiSession implements Session {

/** The Engine that created this session. */
private Engine m_engine;

private String remoteAddress;
private String antiCsrfToken;
private String m_status = ANONYMOUS;

Expand Down Expand Up @@ -490,7 +490,7 @@ public static Session getWikiSession( final Engine engine, final HttpServletRequ
final HttpSession session = request.getSession();
final SessionMonitor monitor = SessionMonitor.getInstance( engine );
final WikiSession wikiSession = ( WikiSession )monitor.find( session );

wikiSession.remoteAddress = request.getRemoteAddr();
// Attach reference to wiki engine
wikiSession.m_engine = engine;
wikiSession.m_cachedLocale = request.getLocale();
Expand Down Expand Up @@ -571,4 +571,9 @@ public static Principal[] userPrincipals( final Engine engine ) {
return monitor.userPrincipals();
}

@Override
public String getRemoteAddress() {
return remoteAddress;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
Expand Down Expand Up @@ -193,6 +194,23 @@ public boolean login( final HttpServletRequest request ) throws WikiSecurityExce
fireEvent( WikiSecurityEvent.LOGIN_ASSERTED, getLoginPrincipal( principals ), session, request);
}
}

if (!session.isAnonymous()) {
final SessionMonitor monitor = SessionMonitor.getInstance(m_engine);
List<Session> sessions = monitor.findOtherSessionsByUsername(session.getLoginPrincipal().getName());
StringBuilder sb = new StringBuilder();
for (Session s : sessions) {
if (s.getRemoteAddress() != null && !s.getRemoteAddress().equals(request.getRemoteAddr())) {
sb.append(request.getRemoteAddr()).append(",");
}
}
if (sb.length() > 0) {
sb.append(request.getRemoteAddr());
LOG.warn("AUDIT - New login for login '" + session.getLoginPrincipal().getName() + "' from " + request.getRemoteAddr()
+ " however there are already concurrent logins from the following addresses " + sb.toString());
fireEvent(WikiSecurityEvent.LOGIN_ALERT, session.getLoginPrincipal(), session, request);
}
}

// If user still anonymous, use the remote address
if( session.isAnonymous() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ Licensed to the Apache Software Foundation (ASF) under one
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -111,12 +113,14 @@ private Session findSession( final HttpSession session ) {
private Session findSession( final String sessionId ) {
Session wikiSession = null;
final String sid = ( sessionId == null ) ? "(null)" : sessionId;
final Session storedSession = m_sessions.get( sid );
synchronized( m_sessions ){
final Session storedSession = m_sessions.get( sid );

// If the weak reference returns a wiki session, return it
if( storedSession != null ) {
LOG.debug( "Looking up WikiSession for session ID={}... found it", sid );
wikiSession = storedSession;
// If the weak reference returns a wiki session, return it
if( storedSession != null ) {
LOG.debug( "Looking up WikiSession for session ID={}... found it", sid );
wikiSession = storedSession;
}
}

return wikiSession;
Expand Down Expand Up @@ -294,4 +298,24 @@ public void sessionDestroyed( final HttpSessionEvent se ) {
}
}

/**
* gets a list of other sessions for the same login id for auditing purposes.
*
* @since 3.0.0
* @param name
* @return list
*/
public List<Session> findOtherSessionsByUsername(String name) {
List<Session> otherSessions = new ArrayList<>();
synchronized (m_sessions) {

for (Session m : m_sessions.values()) {
if (m.getLoginPrincipal().getName().equals(name)) {
otherSessions.add(m);
}
}
}
return otherSessions;
}

}
Loading