org.vaadin.spring.security.internal.VaadinSharedSecurity.java Source code

Java tutorial

Introduction

Here is the source code for org.vaadin.spring.security.internal.VaadinSharedSecurity.java

Source

/*
 * Copyright 2015 The original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.vaadin.spring.security.internal;

import com.vaadin.server.VaadinSession;
import com.vaadin.server.WrappedSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.util.Assert;
import org.vaadin.spring.http.HttpService;
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.authentication.VaadinLogoutHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Implementation of {@link org.vaadin.spring.security.VaadinSecurity} that is used when Vaadin is participating
 * in the existing Spring Web Security setup.
 *
 * @author Petter Holmstrm (petter@vaadin.com)
 * @author Gert-Jan Timmer (gjr.timmer@gmail.com)
 */
public class VaadinSharedSecurity extends AbstractVaadinSecurity {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    HttpService httpRequestResponseHolder;
    @Autowired(required = false)
    SessionAuthenticationStrategy sessionAuthenticationStrategy;
    @Autowired(required = false)
    VaadinAuthenticationSuccessHandler vaadinAuthenticationSuccessHandler;
    @Autowired(required = false)
    VaadinLogoutHandler vaadinLogoutHandler;
    private String springSecurityContextKey = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
    private boolean saveContextInSessionAfterLogin = false;

    @Override
    public Authentication login(Authentication authentication, boolean rememberMe) throws Exception {
        SecurityContext context = SecurityContextHolder.getContext();

        final HttpServletRequest request = httpRequestResponseHolder.getCurrentRequest();
        if (request == null) {
            throw new IllegalStateException("No HttpServletRequest bound to current thread");
        }

        final HttpServletResponse response = httpRequestResponseHolder.getCurrentResponse();
        if (response == null) {
            throw new IllegalStateException("No HttpServletResponse bound to current thread");
        }

        try {
            logger.debug("Attempting authentication of {}, rememberMe = {}", authentication, rememberMe);
            final Authentication fullyAuthenticated = getAuthenticationManager().authenticate(authentication);

            /*
             * Fix: #255 (VaadinSharedSecurity ignored sessionAuthenticationStrategy failures) 
             * 
             * Reorganized Authentication procedure
             * Authentication workflow set according to {@link AbstractAuthenticationProcessingFilter}
             *
             * #1 Check for Null Authentication and handle like Authentication Exception
             *    And set {@link Authentication} Object to null out of security
             *    
             * #2 Execute SessionStrategy
             * #3 Handle Successful login
             * #4 Execute LoginSuccessHandler
             */

            // #1 Check NULL Authentication
            if (authentication == null) {
                // Handle failed authentication
                logger.debug("Authentication failed");
                context = SecurityContextHolder.createEmptyContext();
                if (hasRememberMeServices()) {
                    logger.debug("Invoking RememberMeServices");
                    getRememberMeServices().loginFail(request, response);
                }

                /* 
                 * Return NULL
                 * And set {@link Autentication} object reference to NULL
                 */
                authentication = null;
                return null;
            }

            // #2 Execute SessionStrategy
            logger.debug("Invoking session authentication strategy");
            sessionAuthenticationStrategy.onAuthentication(fullyAuthenticated, request, response);

            // #3 Handle Successful Login
            context.setAuthentication(fullyAuthenticated);
            if (rememberMe) {
                if (hasRememberMeServices()) {
                    logger.debug("Invoking RememberMeServices");
                    getRememberMeServices().loginSuccess(request, response, authentication);
                } else {
                    throw new IllegalStateException(
                            "Requested RememberMe authentication but no RememberBeServices are available");
                }
            }

            // #4 Execute LoginSuccessHandler
            logger.debug("Invoking authentication success handler");
            vaadinAuthenticationSuccessHandler.onAuthenticationSuccess(fullyAuthenticated);

            return authentication;
        } catch (AuthenticationException e) {
            logger.debug("Authentication failed");
            context = SecurityContextHolder.createEmptyContext();
            if (hasRememberMeServices()) {
                logger.debug("Invoking RememberMeServices");
                getRememberMeServices().loginFail(request, response);
            }
            throw e;
        } finally {
            if (saveContextInSessionAfterLogin) {
                logger.debug("Saving security context in the session");
                WrappedSession session = getSession();
                if (session != null) {
                    session.setAttribute(springSecurityContextKey, context);
                } else {
                    logger.warn(
                            "Tried to save security context in the session, but no session was bound to the current thread");
                }
            }
        }
    }

    @Override
    public void logout() {
        vaadinLogoutHandler.onLogout();
    }

    @Override
    public Authentication getAuthentication() {
        final SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication authentication = securityContext.getAuthentication();

        if (authentication == null) {
            // The SecurityContextHolder only holds the Authentication when it is
            // processing the securityFilterChain. After it completes the chain
            // it clears the context holder.

            // Therefore, the Authentication object can be retrieved from the
            // location where the securityFilterChain or VaadinSecurity has left it,
            // within the HttpSession.
            logger.debug("No authentication object bound to thread, trying to access the session directly");
            WrappedSession session = getSession();
            if (session != null) {
                SecurityContext context = (SecurityContext) session.getAttribute(springSecurityContextKey);
                authentication = context.getAuthentication();
            } else {
                logger.debug("No session bound to current thread, cannot retrieve the authentication object");
            }
        }
        return authentication;
    }

    private WrappedSession getSession() {
        VaadinSession vaadinSession = VaadinSession.getCurrent();
        if (vaadinSession != null) {
            return vaadinSession.getSession();
        } else {
            return null;
        }
    }

    /**
     * Sets the session attribute key under which the security context is stored. Defaults to {@link HttpSessionSecurityContextRepository#SPRING_SECURITY_CONTEXT_KEY}.
     */
    public void setSpringSecurityContextKey(String springSecurityContextKey) {
        Assert.hasText(springSecurityContextKey, "springSecurityContextKey cannot be empty");
        this.springSecurityContextKey = springSecurityContextKey;
    }

    /**
     * Specifies whether the security context should be explicitly saved in the session after {@link #login(org.springframework.security.core.Authentication, boolean)}
     * completes. Defaults to false.
     *
     * @see #setSpringSecurityContextKey(String)
     */
    public void setSaveContextInSessionAfterLogin(boolean saveContextInSessionAfterLogin) {
        this.saveContextInSessionAfterLogin = saveContextInSessionAfterLogin;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();
        if (sessionAuthenticationStrategy == null) {
            logger.info("No session authentication strategy found in application context, using null strategy");
            sessionAuthenticationStrategy = new NullAuthenticatedSessionStrategy();
        } else {
            logger.info("Using session authentication strategy {}", sessionAuthenticationStrategy);
        }
        if (vaadinAuthenticationSuccessHandler == null) {
            logger.info("No authentication success handler found in the application context, using null handler");
            vaadinAuthenticationSuccessHandler = new VaadinAuthenticationSuccessHandler.NullHandler();
        } else {
            logger.info("Using authentication success handler {}", vaadinAuthenticationSuccessHandler);
        }
        if (vaadinLogoutHandler == null) {
            logger.info("No logout handler found in the application context, using null handler");
            vaadinLogoutHandler = new VaadinLogoutHandler.NullHandler();
        } else {
            logger.info("Using logout handler {}", vaadinLogoutHandler);
        }
    }

    /**
     * Makes it possible to replace the {@link org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler} after
     * the bean has been configured.
     */
    public void setVaadinAuthenticationSuccessHandler(
            VaadinAuthenticationSuccessHandler vaadinAuthenticationSuccessHandler) {
        this.vaadinAuthenticationSuccessHandler = vaadinAuthenticationSuccessHandler;
    }

    public VaadinAuthenticationSuccessHandler getVaadinAuthenticationSuccessHandler() {
        return vaadinAuthenticationSuccessHandler;
    }

    /**
     * Makes it possible to replace the {@link org.springframework.security.web.authentication.session.SessionAuthenticationStrategy} after
     * the bean has been configured.
     */
    public void setSessionAuthenticationStrategy(SessionAuthenticationStrategy sessionAuthenticationStrategy) {
        this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
    }

    public SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
        return sessionAuthenticationStrategy;
    }

    /**
     * Makes it possible to replace the {@link org.vaadin.spring.security.web.authentication.VaadinLogoutHandler} after the bean has been configured.
     */
    public void setVaadinLogoutHandler(VaadinLogoutHandler vaadinLogoutHandler) {
        this.vaadinLogoutHandler = vaadinLogoutHandler;
    }

    public VaadinLogoutHandler getVaadinLogoutHandler() {
        return vaadinLogoutHandler;
    }
}