com.frequentis.maritime.mcsr.config.SecurityConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for com.frequentis.maritime.mcsr.config.SecurityConfiguration.java

Source

/*
 * MaritimeCloud Service Registry
 * Copyright (c) 2016 Frequentis AG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.frequentis.maritime.mcsr.config;

import com.frequentis.maritime.mcsr.repository.PersistentTokenRepository;
import com.frequentis.maritime.mcsr.security.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;
import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
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.authentication.www.BasicAuthenticationFilter;

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
    private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);

    @Inject
    private JHipsterProperties jHipsterProperties;

    @Inject
    private AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler;

    @Inject
    private AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler;

    @Inject
    private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

    @Inject
    private Http401UnauthorizedEntryPoint authenticationEntryPoint;

    @Inject
    private UserDetailsService userDetailsService;

    @Inject
    private RememberMeServices rememberMeServices;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Inject
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(keycloakAuthenticationProvider()).userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
        ;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        log.debug("Configuring WebSecurity");
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**").antMatchers("/app/**/*.{js,html}")
                .antMatchers("/bower_components/**").antMatchers("/i18n/**").antMatchers("/content/**")
                .antMatchers("/swagger-ui/index.html").antMatchers("/test/**").antMatchers("/h2-console/**");
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    protected BasicAuthenticationFilter basicAuthenticationFilter() {
        try {
            return new BasicAuthenticationFilter(authenticationManager());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
        log.debug("Configuring HttpSecurity");
        log.debug("RememberMe service {}", rememberMeServices);
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and()
                .addFilterBefore(basicAuthenticationFilter(), LogoutFilter.class)
                .addFilterBefore(new SkippingFilter(keycloakPreAuthActionsFilter()), LogoutFilter.class)
                .addFilterBefore(new SkippingFilter(keycloakAuthenticationProcessingFilter()),
                        X509AuthenticationFilter.class)
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()).and()
                //            .addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
                //            .exceptionHandling()
                //            .accessDeniedHandler(new CustomAccessDeniedHandler())
                //            .authenticationEntryPoint(authenticationEntryPoint)
                //        .and()
                .rememberMe().rememberMeServices(rememberMeServices).rememberMeParameter("remember-me")
                .key(jHipsterProperties.getSecurity().getRememberMe().getKey()).and().formLogin()
                .loginProcessingUrl("/api/authentication").successHandler(ajaxAuthenticationSuccessHandler)
                .failureHandler(ajaxAuthenticationFailureHandler).usernameParameter("j_username")
                .passwordParameter("j_password").permitAll().and().logout().logoutUrl("/api/logout")
                .logoutSuccessHandler(ajaxLogoutSuccessHandler).deleteCookies("JSESSIONID", "CSRF-TOKEN")
                .permitAll().and().headers().frameOptions().disable().and().authorizeRequests()
                .antMatchers("/api/register").hasAuthority(AuthoritiesConstants.ADMIN)
                .antMatchers("/api/elasticsearch/**").permitAll().antMatchers("/api/activate").permitAll()
                .antMatchers("/api/authenticate").permitAll()
                .antMatchers("/api/account/reset_password/inactivateit").permitAll()
                .antMatchers("/api/account/reset_password/finish").permitAll().antMatchers("/api/profile-info")
                .permitAll().antMatchers("/websocket/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
                .antMatchers("/websocket/**").permitAll().antMatchers("/management/**")
                .hasAuthority(AuthoritiesConstants.ADMIN).antMatchers("/v2/api-docs/**").permitAll()
                .antMatchers(HttpMethod.PUT, "/api/**").authenticated().antMatchers(HttpMethod.POST, "/api/**")
                .authenticated().antMatchers(HttpMethod.DELETE, "/api/**").authenticated()
                .antMatchers(HttpMethod.TRACE, "/api/**").authenticated().antMatchers(HttpMethod.HEAD, "/api/**")
                .authenticated().antMatchers(HttpMethod.PATCH, "/api/**").authenticated()
                .antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll().antMatchers(HttpMethod.GET, "/api/**")
                .permitAll().antMatchers("/swagger-resources/configuration/ui").permitAll()
                .antMatchers("/swagger-ui/index.html").permitAll().and().csrf().disable();

    }

    @Bean
    public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
        return new SecurityEvaluationContextExtension();
    }

    /**
     * SkippingFilter skips holded filter if user is authenticated.
     *
     * <p>It used as workaround for Keycloak filter.</p>
     *
     */
    class SkippingFilter implements Filter {
        private final Logger log = LoggerFactory.getLogger(SkippingFilter.class);
        private Filter f;

        public SkippingFilter(Filter filter) {
            f = filter;
        }

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            f.init(filterConfig);
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {

            String url = "";
            String queryString = "";
            if (request instanceof HttpServletRequest) {
                url = ((HttpServletRequest) request).getRequestURL().toString();
                queryString = ((HttpServletRequest) request).getQueryString();
            }

            log.debug("Check authentication [" + url + "?" + queryString + "]");
            if (isAuthenticated()) {
                log.debug("Authenticated - skip filter [" + url + "?" + queryString + "]");
                chain.doFilter(request, response);
            } else {
                log.debug("No authentication - do filter [" + url + "?" + queryString + "]");
                f.doFilter(request, response, chain);
            }
        }

        @Override
        public void destroy() {
            f.destroy();
        }

        private boolean isAuthenticated() {
            return SecurityContextHolder.getContext() != null
                    && SecurityContextHolder.getContext().getAuthentication() != null
                    && SecurityContextHolder.getContext().getAuthentication().isAuthenticated();
        }

    }
}