org.moserp.infrastructure.gateway.config.OAuthConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for org.moserp.infrastructure.gateway.config.OAuthConfiguration.java

Source

/*******************************************************************************
 * Copyright 2013 Thomas Letsch (contact@thomas-letsch.de)
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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.moserp.infrastructure.gateway.config;

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * The Class OAuthConfiguration that sets up the OAuth2 single sign on
 * configuration and the web security associated with it.
 */
@Configuration
@EnableResourceServer
public class OAuthConfiguration extends ResourceServerConfigurerAdapter {

    private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";
    private static final String CSRF_ANGULAR_HEADER_NAME = "X-XSRF-TOKEN";

    /**
     * Define the security that applies to the proxy
     */
    public void configure(HttpSecurity http) throws Exception {
        http.logout().and().antMatcher("/**").authorizeRequests()
                .antMatchers("/index.html", "/home.html", "/web/**", "/uaa/oauth/**").permitAll().anyRequest()
                .authenticated().and().csrf().csrfTokenRepository(getCSRFTokenRepository())
                .ignoringAntMatchers("/uaa/oauth/token").and()
                .addFilterAfter(createCSRFHeaderFilter(), CsrfFilter.class);
    }

    /**
     * Spring security offers in-built protection for cross site request forgery
     * (CSRF) by needing a custom token in the header for any requests that are
     * NOT safe i.e. modify the resources from the server e.g. POST, PUT & PATCH
     * etc.<br>
     * <br>
     *
     * This protection is achieved using cookies that send a custom value (would
     * remain same for the session) in the first request and then the front-end
     * would send back the value as a custom header.<br>
     * <br>
     *
     * In this method we create a filter that is applied to the web security as
     * follows:
     * <ol>
     * <li>Spring security provides the CSRF token value as a request attribute;
     * so we extract it from there.</li>
     * <li>If we have the token, Angular wants the cookie name to be
     * "XSRF-TOKEN". So we add the cookie if it's not there and set the path for
     * the cookie to be "/" which is root. In more complicated cases, this might
     * have to be the context root of the api gateway.</li>
     * <li>We forward the request to the next filter in the chain</li>
     * </ol>
     *
     * The request-to-cookie filter that we add needs to be after the
     * <code>csrf()</code> filter so that the request attribute for CsrfToken
     * has been already added before we start to process it.
     *
     * @return
     */
    private Filter createCSRFHeaderFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                    FilterChain filterChain) throws ServletException, IOException {
                CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
                    String token = csrf.getToken();
                    if (cookie == null || token != null && !token.equals(cookie.getValue())) {
                        cookie = new Cookie(CSRF_COOKIE_NAME, token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }

    /**
     * Angular sends the CSRF token in a custom header named "X-XSRF-TOKEN"
     * rather than the default "X-CSRF-TOKEN" that Spring security expects.
     * Hence we are now telling Spring security to expect the token in the
     * "X-XSRF-TOKEN" header.<br><br>
     *
     * This customization is added to the <code>csrf()</code> filter.
     *
     * @return
     */
    private CsrfTokenRepository getCSRFTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName(CSRF_ANGULAR_HEADER_NAME);
        return repository;
    }
}