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}