org.vaadin.spring.security.shared.DefaultVaadinSharedSecurity.java Source code

Java tutorial

Introduction

Here is the source code for org.vaadin.spring.security.shared.DefaultVaadinSharedSecurity.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.shared;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
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.AbstractVaadinSecurity;

import com.vaadin.server.VaadinSession;
import com.vaadin.server.WrappedSession;

/**
 * Default implementation of {@link VaadinSharedSecurity}.
 *
 * @author Petter Holmstrm (petter@vaadin.com)
 * @author Gert-Jan Timmer (gjr.timmer@gmail.com)
 */
public class DefaultVaadinSharedSecurity extends AbstractVaadinSecurity implements VaadinSharedSecurity {

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultVaadinSharedSecurity.class);

    @Autowired
    HttpService httpService;
    @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 {
        final HttpServletRequest request = new RememberMeRequestWrapper(getCurrentRequest(), rememberMe,
                getRememberMeParameter());
        final HttpServletResponse response = getCurrentResponse();

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

            LOGGER.debug("Invoking session authentication strategy");
            sessionAuthenticationStrategy.onAuthentication(fullyAuthenticated, request, response);

            successfulAuthentication(fullyAuthenticated, request, response);
            return fullyAuthenticated;
        } catch (Exception e) {
            unsuccessfulAuthentication(request, response);
            throw e;
        } finally {
            if (saveContextInSessionAfterLogin) {
                LOGGER.debug("Saving security context in the session");
                WrappedSession session = getSession();
                if (session != null) {
                    session.setAttribute(springSecurityContextKey, SecurityContextHolder.getContext());
                } else {
                    LOGGER.warn(
                            "Tried to save security context in the session, but no session was bound to the current thread");
                }
            }
        }
    }

    /**
     * Returns the name of the request parameter that enables or disables remember me authentication. If the
     * {@link #getRememberMeServices() RememberMeServices} extends {@link AbstractRememberMeServices},
     * the parameter will be retrieved from there. Otherwise, {@link AbstractRememberMeServices#DEFAULT_PARAMETER} is
     * returned.
     */
    protected String getRememberMeParameter() {
        if (getRememberMeServices() instanceof AbstractRememberMeServices) {
            return ((AbstractRememberMeServices) getRememberMeServices()).getParameter();
        } else {
            return AbstractRememberMeServices.DEFAULT_PARAMETER;
        }
    }

    /**
     * Called by {@link #login(Authentication, boolean)} upon unsuccessful authentication. This implementation will
     * clear the security context holder and inform the {@code RememberMeServices} of the failed login.
     * 
     * @param request the current request.
     * @param response the current response.
     */
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response) {
        LOGGER.debug("Authentication failed");
        SecurityContextHolder.clearContext();
        getRememberMeServices().loginFail(request, response);
    }

    /**
     * Called by {@link #login(Authentication, boolean)} upon successful authentication. This implementation will
     * update the security context holder, inform the {@code RememberMeServices} and invoke the authentication success
     * handler.
     *
     * @param authentication the authentication token returned by the
     *        {@link org.springframework.security.authentication.AuthenticationManager}.
     * @param request the current request.
     * @param response the current response.
     * @throws Exception
     */
    protected void successfulAuthentication(Authentication authentication, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        LOGGER.debug("Authentication succeeded");
        SecurityContextHolder.getContext().setAuthentication(authentication);
        getRememberMeServices().loginSuccess(request, response, authentication);
        vaadinAuthenticationSuccessHandler.onAuthenticationSuccess(authentication);
    }

    /**
     * Returns the HTTP request bound to the current thread.
     */
    protected HttpServletRequest getCurrentRequest() {
        final HttpServletRequest request = httpService.getCurrentRequest();
        if (request == null) {
            throw new IllegalStateException("No HttpServletRequest bound to current thread");
        }
        return request;
    }

    /**
     * Returns the HTTP response bound to the current thread.
     */
    protected HttpServletResponse getCurrentResponse() {
        final HttpServletResponse response = httpService.getCurrentResponse();
        if (response == null) {
            throw new IllegalStateException("No HttpServletResponse bound to current thread");
        }
        return response;
    }

    @Override
    public Authentication login(String username, String password, boolean rememberMe) throws Exception {
        return login(new UsernamePasswordAuthenticationToken(username, password), rememberMe);
    }

    @Override
    public Authentication login(Authentication authentication) throws Exception {
        return login(authentication, false);
    }

    @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 static 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 VaadinAuthenticationSuccessHandler} after
     * the bean has been configured.
     */
    public void setVaadinAuthenticationSuccessHandler(
            VaadinAuthenticationSuccessHandler vaadinAuthenticationSuccessHandler) {
        this.vaadinAuthenticationSuccessHandler = vaadinAuthenticationSuccessHandler;
    }

    protected 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;
    }

    protected SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
        return sessionAuthenticationStrategy;
    }

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

    protected VaadinLogoutHandler getVaadinLogoutHandler() {
        return vaadinLogoutHandler;
    }

    /**
     * A request wrapper that overrides the value of the remember me parameter based on the values provided in the
     * constructor. This makes it possible to plug into the existing remember me architecture of Spring Security.
     */
    protected final class RememberMeRequestWrapper extends HttpServletRequestWrapper {

        private final String parameter;
        private final String rememberMe;

        public RememberMeRequestWrapper(HttpServletRequest request, boolean rememberMe, String parameter) {
            super(request);
            this.rememberMe = Boolean.toString(rememberMe);
            this.parameter = parameter;
        }

        @Override
        public String getParameter(String name) {
            if (parameter.equals(name)) {
                return rememberMe;
            }
            return super.getParameter(name);
        }
    }
}