001 /* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019 package org.apache.wiki.event; 020 021 import java.security.Principal; 022 023 import org.apache.commons.lang.ArrayUtils; 024 import org.apache.log4j.Level; 025 import org.apache.log4j.Logger; 026 027 import org.apache.wiki.event.WikiEvent; 028 029 /** 030 * <p>Event class for security events: login/logout, wiki group adds/changes, and 031 * authorization decisions. When a WikiSecurityEvent is constructed, the 032 * security logger {@link #log} is notified.</p> 033 * <p>These events are logged with priority <code>ERROR</code>:</p> 034 * <ul> 035 * <li>login failed - bad credential or password</li> 036 * </ul> 037 * <p>These events are logged with priority <code>WARN</code>:</p> 038 * <ul> 039 * <li>access denied</li> 040 * <li>login failed - credential expired</li> 041 * <li>login failed - account expired</li> 042 * </ul> 043 * <p>These events are logged with priority <code>INFO</code>:</p> 044 * <ul> 045 * <li>login succeeded</li> 046 * <li>logout</li> 047 * <li>user profile name changed</li> 048 * </ul> 049 * <p>These events are logged with priority <code>DEBUG</code>:</p> 050 * <ul> 051 * <li>access allowed</li> 052 * <li>add group</li> 053 * <li>remove group</li> 054 * <li>clear all groups</li> 055 * <li>add group member</li> 056 * <li>remove group member</li> 057 * <li>clear all members from group</li> 058 * </ul> 059 * @since 2.3.79 060 */ 061 public final class WikiSecurityEvent extends WikiEvent 062 { 063 064 private static final long serialVersionUID = -6751950399721334496L; 065 066 /** When a user's attempts to log in as guest, via cookies, using a password or otherwise. */ 067 public static final int LOGIN_INITIATED = 30; 068 069 /** When a user first accesses JSPWiki, but before logging in or setting a cookie. */ 070 public static final int LOGIN_ANONYMOUS = 31; 071 072 /** When a user sets a cookie to assert their identity. */ 073 public static final int LOGIN_ASSERTED = 32; 074 075 /** When a user authenticates with a username and password, or via container auth. */ 076 public static final int LOGIN_AUTHENTICATED = 40; 077 078 /** When a login fails due to account expiration. */ 079 public static final int LOGIN_ACCOUNT_EXPIRED = 41; 080 081 /** When a login fails due to credential expiration. */ 082 public static final int LOGIN_CREDENTIAL_EXPIRED = 42; 083 084 /** When a login fails due to wrong username or password. */ 085 public static final int LOGIN_FAILED = 43; 086 087 /** When a user logs out. */ 088 public static final int LOGOUT = 44; 089 090 /** When a Principal should be added to the WikiSession */ 091 public static final int PRINCIPAL_ADD = 35; 092 093 /** When a session expires. */ 094 public static final int SESSION_EXPIRED = 45; 095 096 /** When a new wiki group is added. */ 097 public static final int GROUP_ADD = 46; 098 099 /** When a wiki group is deleted. */ 100 public static final int GROUP_REMOVE = 47; 101 102 /** When all wiki groups are removed from GroupDatabase. */ 103 public static final int GROUP_CLEAR_GROUPS = 48; 104 105 /** When access to a resource is allowed. */ 106 public static final int ACCESS_ALLOWED = 51; 107 108 /** When access to a resource is allowed. */ 109 public static final int ACCESS_DENIED = 52; 110 111 /** When a user profile is saved. */ 112 public static final int PROFILE_SAVE = 53; 113 114 /** When a user profile name changes. */ 115 public static final int PROFILE_NAME_CHANGED = 54; 116 117 /** The security logging service. */ 118 protected static final Logger log = Logger.getLogger( "SecurityLog" ); 119 120 private final Principal m_principal; 121 122 private final Object m_target; 123 124 private static final int[] ERROR_EVENTS = { LOGIN_FAILED }; 125 126 private static final int[] WARN_EVENTS = { LOGIN_ACCOUNT_EXPIRED, 127 LOGIN_CREDENTIAL_EXPIRED }; 128 129 private static final int[] INFO_EVENTS = { LOGIN_AUTHENTICATED, 130 SESSION_EXPIRED, LOGOUT, PROFILE_NAME_CHANGED }; 131 132 /** 133 * Constructs a new instance of this event type, which signals a security 134 * event has occurred. The <code>source</code> parameter is required, and 135 * may not be <code>null</code>. When the WikiSecurityEvent is 136 * constructed, the security logger {@link #log} is notified. 137 * @param src the source of the event, which can be any object: a wiki 138 * page, group or authentication/authentication/group manager. 139 * @param type the type of event 140 * @param principal the subject of the event, which may be <code>null</code> 141 * @param target the changed Object, which may be <code>null</code> 142 */ 143 public WikiSecurityEvent( Object src, int type, Principal principal, Object target ) 144 { 145 super( src, type ); 146 if ( src == null ) 147 { 148 throw new IllegalArgumentException( "Argument(s) cannot be null." ); 149 } 150 this.m_principal = principal; 151 this.m_target = target; 152 if ( log.isEnabledFor( Level.ERROR ) && ArrayUtils.contains( ERROR_EVENTS, type ) ) 153 { 154 log.error( this ); 155 } 156 else if ( log.isEnabledFor( Level.WARN ) && ArrayUtils.contains( WARN_EVENTS, type ) ) 157 { 158 log.warn( this ); 159 } 160 else if ( log.isEnabledFor( Level.INFO ) && ArrayUtils.contains( INFO_EVENTS, type ) ) 161 { 162 log.info( this ); 163 } 164 log.debug( this ); 165 } 166 167 /** 168 * Constructs a new instance of this event type, which signals a security 169 * event has occurred. The <code>source</code> parameter is required, and 170 * may not be <code>null</code>. When the WikiSecurityEvent is 171 * constructed, the security logger {@link #log} is notified. 172 * @param src the source of the event, which can be any object: a wiki 173 * page, group or authentication/authentication/group manager. 174 * @param type the type of event 175 * @param target the changed Object, which may be <code>null</code>. 176 */ 177 public WikiSecurityEvent( Object src, int type, Object target ) 178 { 179 this( src, type, null, target ); 180 } 181 182 /** 183 * Returns the principal to whom the opeation applied, if supplied. This 184 * method may return <code>null</code> 185 * <em>— and calling methods should check for this condition</em>. 186 * @return the changed object 187 */ 188 public Object getPrincipal() 189 { 190 return m_principal; 191 } 192 193 /** 194 * Returns the object that was operated on, if supplied. This method may 195 * return <code>null</code> 196 * <em>— and calling methods should check for this condition</em>. 197 * @return the changed object 198 */ 199 public Object getTarget() 200 { 201 return m_target; 202 } 203 204 /** 205 * Prints a String (human-readable) representation of this object. 206 * @see java.lang.Object#toString() 207 */ 208 public String toString() 209 { 210 StringBuffer msg = new StringBuffer(); 211 msg.append( "WikiSecurityEvent." ); 212 msg.append( eventName( getType() ) ); 213 Object obj = getSrc(); // cfr. https://forums.oracle.com/forums/thread.jspa?threadID=1184115 214 msg.append( " [source=" + obj.toString() ); 215 if( m_principal != null ) 216 { 217 msg.append( ", princpal=" + m_principal.getClass().getName() ); 218 msg.append( " " + m_principal.getName() ); 219 } 220 msg.append( ", target=" + m_target ); 221 msg.append( "]" ); 222 return msg.toString(); 223 } 224 225 /** 226 * Returns a textual representation of an event type. 227 * @param type the type 228 * @return the string representation 229 */ 230 public String eventName( int type ) 231 { 232 switch( type ) 233 { 234 case LOGIN_AUTHENTICATED: return "LOGIN_AUTHENTICATED"; 235 case LOGIN_ACCOUNT_EXPIRED: return "LOGIN_ACCOUNT_EXPIRED"; 236 case LOGIN_CREDENTIAL_EXPIRED: return "LOGIN_ACCOUNT_EXPIRED"; 237 case LOGIN_FAILED: return "LOGIN_FAILED"; 238 case LOGOUT: return "LOGOUT"; 239 case PRINCIPAL_ADD: return "PRINCIPAL_ADD"; 240 case SESSION_EXPIRED: return "SESSION_EXPIRED"; 241 case GROUP_ADD: return "GROUP_ADD"; 242 case GROUP_REMOVE: return "GROUP_REMOVE"; 243 case GROUP_CLEAR_GROUPS: return "GROUP_CLEAR_GROUPS"; 244 case ACCESS_ALLOWED: return "ACCESS_ALLOWED"; 245 case ACCESS_DENIED: return "ACCESS_DENIED"; 246 case PROFILE_NAME_CHANGED: return "PROFILE_NAME_CHANGED"; 247 case PROFILE_SAVE: return "PROFILE_SAVE"; 248 default: return super.eventName(); 249 } 250 } 251 252 /** 253 * Returns a human-readable description of the event type. 254 * 255 * @return a String description of the type 256 */ 257 public String getTypeDescription() 258 { 259 switch ( getType() ) 260 { 261 case LOGIN_AUTHENTICATED: return "login authenticated"; 262 case LOGIN_ACCOUNT_EXPIRED: return "login failed: expired account"; 263 case LOGIN_CREDENTIAL_EXPIRED: return "login failed: credential expired"; 264 case LOGIN_FAILED: return "login failed"; 265 case LOGOUT: return "user logged out"; 266 case PRINCIPAL_ADD: return "new principal added"; 267 case SESSION_EXPIRED: return "session expired"; 268 case GROUP_ADD: return "new group added"; 269 case GROUP_REMOVE: return "group removed"; 270 case GROUP_CLEAR_GROUPS: return "all groups cleared"; 271 case ACCESS_ALLOWED: return "access allowed"; 272 case ACCESS_DENIED: return "access denied"; 273 case PROFILE_NAME_CHANGED: return "user profile name changed"; 274 case PROFILE_SAVE: return "user profile saved"; 275 default: return super.getTypeDescription(); 276 } 277 } 278 279 }