package 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. import java.util.regex.*; import javax.mail.internet.*; import org.apache.wicket.*; import org.apache.wicket.protocol.http.WebSession; import org.apache.wicket.request.http.WebRequest; import org.apache.wicket.request.http.WebResponse; import votorola.a.*; import votorola.a.trust.*; import votorola.a.voter.*; import votorola.a.web.wic.authen.*; import votorola.g.lang.*; import votorola.s.wic.count.*; import static votorola.a.voter.IDPair.NOBODY; /** A user session in the Wicket web interface. */ public final @ThreadSafe class VSession extends WebSession implements ServiceSession { /** Creates a VSession. */ VSession( final WebRequest request, WebResponse _response, final VOWicket app ) { super( request ); if( app == null ) throw new IllegalStateException( "null application" ); if( isTemporary() ) bind(); // Make the session stateful even if only stateless pages are being accessed. // Otherwise common coding patterns like storing a feedback message for // WP_Message to display cease to work; not to mention all the session scopes // defined in the scope*() methods below. scopeOpenIDReturn = app.authenticator() instanceof OpenIDAuthenticator? new WP_OpenIDReturn.SessionScope(VSession.this): null; } // ------------------------------------------------------------------------------------ /** The session scope for instances of NavBar. */ NavBar.SessionScope scopeNavBar() { return scopeNavBar; } private final NavBar.SessionScope scopeNavBar = new NavBar.SessionScope( VSession.this ); /** The session scope for instances of WP_OpenIDReturn, or null if the {@linkplain * VOWicket#authenticator() authenticator} is not OpenIDAuthenticator. */ public WP_OpenIDReturn.SessionScope scopeOpenIDReturn() { return scopeOpenIDReturn; } private final WP_OpenIDReturn.SessionScope scopeOpenIDReturn; /** The session scope for instances of WP_Poll. */ public WP_Poll.SessionScope scopePoll() { return scopePoll; } private final WP_Poll.SessionScope scopePoll = new WP_Poll.SessionScope( VSession.this ); /** The session scope for instances of VoterPage. */ public VoterPage.SessionScope scopeVoterPage() { return scopeVoterPage; } private final VoterPage.SessionScope scopeVoterPage = new VoterPage.SessionScope( VSession.this ); /** Pattern to strip from an HTTP URI the mangling that occurs temporarily for new * sessions. The stripped version is returned in group 1. */ public static final Pattern URI_STRIP_PATTERN = Pattern.compile( "^(.+?)\\.?;jsessionid=[0-9A-F]+$" ); // http://etc.etc/PageName;jsessionid=A17ETCETC // http://etc.etc/dir/.;jsessionid=A17ETCETC (the dot appears only for directories) /** Returns the stripped version of the HTTP URI string if it matches {@linkplain * #URI_STRIP_PATTERN URI_STRIP_PATTERN}; otherwise the original string. */ public static final String uriStripped( final String uriString ) { final Matcher m = URI_STRIP_PATTERN.matcher( uriString ); return m.matches()? m.group(1): uriString; } /** @see #getApplication() */ public VOWicket vApplication() { return (VOWicket)getApplication(); } // rather than override getApplication(), because some of these getX methods are final, so use vX for all // - S e r v i c e - S e s s i o n ---------------------------------------------------- public User user() { return user; } private volatile User user; /** Sets the authenticated user. * * @see User#isPersistent() * @see User#traceNode() * * @see #clearUser(VRequestCycle) * @throws NullPointerException if 'id' is null. */ public void setUser( final IDPair id, final boolean persistent, final TraceNode traceNode, final VRequestCycle cycle ) { user = new User( id, persistent, traceNode ); syncUser( cycle ); } /** Clears the authenticated user. * * @see #setUser(IDPair,boolean,TraceNode,VRequestCycle) */ public void clearUser( final VRequestCycle cycle ) { user = null; syncUser( cycle ); } private void syncUser( final VRequestCycle cycle ) { dirty(); // per Session API VPageHTML.addSessionStateCookie( VPageHTML.encodeSessionStateCookieValue(user), cycle.getRequest().getContextPath(), cycle.vResponse() ); } public User userOrNobody() { User u = user; // snapshot copy for atomic test/return if( u == null ) u = User.UNKNOWN; return u; } // - S e s s i o n -------------------------------------------------------------------- /** Returns the session associated with the current thread. Note that in Wicket 1.5, * component.{@linkplain Component#getSession() getSession}() is no * longer faster than this method. * * @see Session#get() */ public static VSession get() { return (VSession)Session.get(); } // ==================================================================================== /** An authenticated Wicket user. */ public static @ThreadSafe final class User extends IDPair implements AuthenticatedUser, java.io.Serializable { private static final long serialVersionUID = 0L; private User( final IDPair id, boolean _persistent, TraceNode _traceNode ) { super( id ); persistent = _persistent; traceNode = _traceNode; } private static final User UNKNOWN = new User( IDPair.NOBODY, false, null ); // -------------------------------------------------------------------------------- /** Answers whether the authenticity of this user was persisted in client cookies * at the time of authentication. */ public boolean isPersistent() { return persistent; } private final boolean persistent; /** The user's node in the neighbourhood trust network, or null if there is none. */ public TraceNode traceNode() { return traceNode; } private final TraceNode traceNode; // - A u t h e n t i c a t e d - U s e r ------------------------------------------ public int trustLevel() { return traceNode == null? 0: traceNode.trustLevel(); } } }