001package votorola.a.web.wic; // Copyright 2008-2012, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import java.util.regex.*; 004import javax.mail.internet.*; 005import org.apache.wicket.*; 006import org.apache.wicket.protocol.http.WebSession; 007import org.apache.wicket.request.http.WebRequest; 008import org.apache.wicket.request.http.WebResponse; 009import votorola.a.*; 010import votorola.a.trust.*; 011import votorola.a.voter.*; 012import votorola.a.web.wic.authen.*; 013import votorola.g.lang.*; 014import votorola.s.wic.count.*; 015 016import static votorola.a.voter.IDPair.NOBODY; 017 018 019/** A user session in the Wicket web interface. 020 */ 021public final @ThreadSafe class VSession extends WebSession implements ServiceSession 022{ 023 024 025 /** Creates a VSession. 026 */ 027 VSession( final WebRequest request, WebResponse _response, final VOWicket app ) 028 { 029 super( request ); 030 if( app == null ) throw new IllegalStateException( "null application" ); 031 032 if( isTemporary() ) bind(); 033 // Make the session stateful even if only stateless pages are being accessed. 034 // Otherwise common coding patterns like storing a feedback message for 035 // WP_Message to display cease to work; not to mention all the session scopes 036 // defined in the scope*() methods below. 037 scopeOpenIDReturn = app.authenticator() instanceof OpenIDAuthenticator? 038 new WP_OpenIDReturn.SessionScope(VSession.this): null; 039 } 040 041 042 043 // ------------------------------------------------------------------------------------ 044 045 046 /** The session scope for instances of NavBar. 047 */ 048 NavBar.SessionScope scopeNavBar() { return scopeNavBar; } 049 050 051 private final NavBar.SessionScope scopeNavBar = new NavBar.SessionScope( VSession.this ); 052 053 054 055 /** The session scope for instances of WP_OpenIDReturn, or null if the {@linkplain 056 * VOWicket#authenticator() authenticator} is not OpenIDAuthenticator. 057 */ 058 public WP_OpenIDReturn.SessionScope scopeOpenIDReturn() { return scopeOpenIDReturn; } 059 060 061 private final WP_OpenIDReturn.SessionScope scopeOpenIDReturn; 062 063 064 065 /** The session scope for instances of WP_Poll. 066 */ 067 public WP_Poll.SessionScope scopePoll() { return scopePoll; } 068 069 070 private final WP_Poll.SessionScope scopePoll = new WP_Poll.SessionScope( VSession.this ); 071 072 073 074 /** The session scope for instances of VoterPage. 075 */ 076 public VoterPage.SessionScope scopeVoterPage() { return scopeVoterPage; } 077 078 079 private final VoterPage.SessionScope scopeVoterPage = new VoterPage.SessionScope( 080 VSession.this ); 081 082 083 084 /** Pattern to strip from an HTTP URI the mangling that occurs temporarily for new 085 * sessions. The stripped version is returned in group 1. 086 */ 087 public static final Pattern URI_STRIP_PATTERN = Pattern.compile( 088 "^(.+?)\\.?;jsessionid=[0-9A-F]+$" ); 089 // http://etc.etc/PageName;jsessionid=A17ETCETC 090 // http://etc.etc/dir/.;jsessionid=A17ETCETC (the dot appears only for directories) 091 092 093 094 /** Returns the stripped version of the HTTP URI string if it matches {@linkplain 095 * #URI_STRIP_PATTERN URI_STRIP_PATTERN}; otherwise the original string. 096 */ 097 public static final String uriStripped( final String uriString ) 098 { 099 final Matcher m = URI_STRIP_PATTERN.matcher( uriString ); 100 return m.matches()? m.group(1): uriString; 101 } 102 103 104 105 /** @see #getApplication() 106 */ 107 public VOWicket vApplication() { return (VOWicket)getApplication(); } // rather than override getApplication(), because some of these getX methods are final, so use vX for all 108 109 110 // - S e r v i c e - S e s s i o n ---------------------------------------------------- 111 112 113 public User user() { return user; } 114 115 116 private volatile User user; 117 118 119 /** Sets the authenticated user. 120 * 121 * @see User#isPersistent() 122 * @see User#traceNode() 123 * 124 * @see #clearUser(VRequestCycle) 125 * @throws NullPointerException if 'id' is null. 126 */ 127 public void setUser( final IDPair id, final boolean persistent, final TraceNode traceNode, 128 final VRequestCycle cycle ) 129 { 130 user = new User( id, persistent, traceNode ); 131 syncUser( cycle ); 132 } 133 134 135 /** Clears the authenticated user. 136 * 137 * @see #setUser(IDPair,boolean,TraceNode,VRequestCycle) 138 */ 139 public void clearUser( final VRequestCycle cycle ) 140 { 141 user = null; 142 syncUser( cycle ); 143 } 144 145 146 private void syncUser( final VRequestCycle cycle ) 147 { 148 dirty(); // per Session API 149 VPageHTML.addSessionStateCookie( VPageHTML.encodeSessionStateCookieValue(user), 150 cycle.getRequest().getContextPath(), cycle.vResponse() ); 151 } 152 153 154 155 public User userOrNobody() 156 { 157 User u = user; // snapshot copy for atomic test/return 158 if( u == null ) u = User.UNKNOWN; 159 return u; 160 } 161 162 163 164 // - S e s s i o n -------------------------------------------------------------------- 165 166 167 /** Returns the session associated with the current thread. Note that in Wicket 1.5, 168 * <code>component.{@linkplain Component#getSession() getSession}()</code> is no 169 * longer faster than this method. 170 * 171 * @see Session#get() 172 */ 173 public static VSession get() { return (VSession)Session.get(); } 174 175 176 177 // ==================================================================================== 178 179 180 /** An authenticated Wicket user. 181 */ 182 public static @ThreadSafe final class User extends IDPair 183 implements AuthenticatedUser, java.io.Serializable 184 { 185 186 private static final long serialVersionUID = 0L; 187 188 189 private User( final IDPair id, boolean _persistent, TraceNode _traceNode ) 190 { 191 super( id ); 192 persistent = _persistent; 193 traceNode = _traceNode; 194 } 195 196 197 private static final User UNKNOWN = new User( IDPair.NOBODY, false, null ); 198 199 200 // -------------------------------------------------------------------------------- 201 202 203 /** Answers whether the authenticity of this user was persisted in client cookies 204 * at the time of authentication. 205 */ 206 public boolean isPersistent() { return persistent; } 207 208 209 private final boolean persistent; 210 211 212 /** The user's node in the neighbourhood trust network, or null if there is none. 213 */ 214 public TraceNode traceNode() { return traceNode; } 215 216 217 private final TraceNode traceNode; 218 219 220 // - A u t h e n t i c a t e d - U s e r ------------------------------------------ 221 222 223 public int trustLevel() { return traceNode == null? 0: traceNode.trustLevel(); } 224 225 } 226 227 228 229}