001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.authroles.authentication;
018
019import java.util.concurrent.atomic.AtomicBoolean;
020
021import org.apache.wicket.Session;
022import org.apache.wicket.request.Request;
023
024/**
025 * Basic authenticated web session. Subclasses must provide a method that authenticates the session
026 * based on a username and password, and a method implementation that gets the Roles
027 * 
028 * @author Jonathan Locke
029 */
030public abstract class AuthenticatedWebSession extends AbstractAuthenticatedWebSession
031{
032        private static final long serialVersionUID = 1L;
033
034        /**
035         * @return Current authenticated web session
036         */
037        public static AuthenticatedWebSession get()
038        {
039                return (AuthenticatedWebSession)Session.get();
040        }
041
042        /** True when the user is signed in */
043        private final AtomicBoolean signedIn = new AtomicBoolean(false);
044
045        /**
046         * Construct.
047         * 
048         * @param request
049         *            The current request object
050         */
051        public AuthenticatedWebSession(Request request)
052        {
053                super(request);
054        }
055
056        /**
057         * Try to sign in the user. It'll call {@link #authenticate(String, String)} to do the real work
058         * and that is what you need to subclass to provide your own authentication mechanism.
059         * 
060         * @param username
061         * @param password
062         * @return true, if logon was successful
063         */
064        public final boolean signIn(final String username, final String password)
065        {
066                boolean authenticated = authenticate(username, password);
067
068                if (!authenticated && signedIn.get())
069                {
070                        signOut();
071                }
072                else if (authenticated && signedIn.compareAndSet(false, true))
073                {
074                        bind();
075                }
076                return authenticated;
077        }
078
079        /**
080         * Actual authentication check, has to be implemented by subclasses.
081         * 
082         * @param username
083         *            The username
084         * @param password
085         *            The password
086         * @return True if the user was authenticated successfully
087         */
088        protected abstract boolean authenticate(final String username, final String password);
089
090        /**
091         * Cookie based logins (remember me) may not rely on putting username and password into the
092         * cookie but something else that safely identifies the user. This method is meant to support
093         * these use cases.
094         * 
095         * It is protected (and not public) to enforce that cookie based authentication gets implemented
096         * in a subclass (like you need to implement {@link #authenticate(String, String)} for 'normal'
097         * authentication).
098         * 
099         * @see #authenticate(String, String)
100         * 
101         * @param value
102         */
103        protected final void signIn(boolean value)
104        {
105                signedIn.set(value);
106        }
107
108        /**
109         * @return true, if user is signed in
110         */
111        @Override
112        public final boolean isSignedIn()
113        {
114                return signedIn.get();
115        }
116
117        /**
118         * Sign the user out.
119         * <p>This method is an alias of {@link #invalidate()}</p>
120         */
121        public void signOut()
122        {
123                invalidate();
124        }
125
126        /**
127         * Call signOut() and remove the logon data from where ever they have been persisted (e.g.
128         * Cookies)
129         */
130        @Override
131        public void invalidate()
132        {
133                signedIn.set(false);
134                super.invalidate();
135        }
136}