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.tynamo.security.shiro.authc;
020    
021    import javax.servlet.ServletRequest;
022    import javax.servlet.ServletResponse;
023    
024    import org.apache.shiro.authc.AuthenticationException;
025    import org.apache.shiro.authc.AuthenticationToken;
026    import org.apache.shiro.authc.UsernamePasswordToken;
027    import org.apache.shiro.subject.Subject;
028    
029    /**
030     * An <code>AuthenticationFilter</code> that is capable of automatically performing an authentication attempt
031     * based on the incoming request.
032     *
033     * @since 0.4.0
034     */
035    public abstract class AuthenticatingFilter extends AuthenticationFilter {
036    
037        //TODO - complete JavaDoc
038    
039        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
040            AuthenticationToken token = createToken(request, response);
041            if (token == null) {
042                String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
043                        "must be created in order to execute a login attempt.";
044                throw new IllegalStateException(msg);
045            }
046            try {
047                Subject subject = getSubject(request, response);
048                subject.login(token);
049                return onLoginSuccess(token, subject, request, response);
050            } catch (AuthenticationException e) {
051                return onLoginFailure(token, e, request, response);
052            }
053        }
054    
055        protected abstract AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception;
056    
057        protected AuthenticationToken createToken(String username, String password,
058                                                  ServletRequest request, ServletResponse response) {
059            boolean rememberMe = isRememberMe(request);
060            String host = getHost(request);
061            return createToken(username, password, rememberMe, host);
062        }
063    
064        protected AuthenticationToken createToken(String username, String password,
065                                                  boolean rememberMe, String host) {
066            return new UsernamePasswordToken(username, password, rememberMe, host);
067        }
068    
069        protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
070                                         ServletRequest request, ServletResponse response) throws Exception {
071            return true;
072        }
073    
074        protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e,
075                                         ServletRequest request, ServletResponse response) {
076            return false;
077        }
078    
079        /**
080         * Returns the host name or IP associated with the current subject.  This method is primarily provided for use
081         * during construction of an <code>AuthenticationToken</code>.
082         * <p/>
083         * The default implementation merely returns {@link ServletRequest#getRemoteHost()}.
084         *
085         * @param request the incoming ServletRequest
086         * @return the <code>InetAddress</code> to associate with the login attempt.
087         */
088        protected String getHost(ServletRequest request) {
089            return request.getRemoteHost();
090        }
091    
092        /**
093         * Returns <code>true</code> if &quot;rememberMe&quot; should be enabled for the login attempt associated with the
094         * current <code>request</code>, <code>false</code> otherwise.
095         * <p/>
096         * This implementation always returns <code>false</code> and is provided as a template hook to subclasses that
097         * support <code>rememberMe</code> logins and wish to determine <code>rememberMe</code> in a custom mannner
098         * based on the current <code>request</code>.
099         *
100         * @param request the incoming ServletRequest
101         * @return <code>true</code> if &quot;rememberMe&quot; should be enabled for the login attempt associated with the
102         *         current <code>request</code>, <code>false</code> otherwise.
103         */
104        protected boolean isRememberMe(ServletRequest request) {
105            return false;
106        }
107    }