So konfigurieren Sie die Waffel im Frühjahr mithilfe der Java-Konfiguration


Pablo Jomer:

Ich habe mich bemüht, die Waffel mit Spring 4.2.5 unter Verwendung der Spring Java-Konfiguration zum Laufen zu bringen. Und ich dachte, ich könnte genauso gut anderen in der gleichen Situation helfen.

Wir verwenden einen benutzerdefinierten PreWaffle- und PostWaffle-Filter, um zu authentifizieren, dass der Benutzer in unserer Datenbank vorhanden ist, nachdem er über das NTLM-Protokoll für Waffeln validiert wurde.

Wir haben auch Methoden zum Autorisieren von Benutzeraktionen mithilfe der EnableGlobalMethodSecurity-Annotation.

Um dies im Frühjahr zum Laufen zu bringen, war die Java-Konfiguration, gelinde gesagt, ein Problem. Unsere Lösung finden Sie in der Antwort unten. Ich hoffe es wird helfen.

Pablo Jomer:

SpringConfiguration.java

// ... imports 
@Configuration
@EnableWebMvc
@EnableScheduling
@PropertySources({
    @PropertySource("classpath:app.properties")
    // ... Properties sources
})
@EnableTransactionManagement
@ComponentScan(basePackages = "com.our.package")
public class SpringConfiguration extends WebMvcConfigurerAdapter {

 // Our Spring configuration ...

}

SecurityConfiguration.java

// ... imports 
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
@Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

  // Authentication manager configuration
  @Autowired
  private WindowsAuthenticationProviderWrapper authProvider;

  @Autowired
  private AuthenticationManagerBuilder auth;

  @Override
  protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authProvider);
  }

  @Bean
  public AuthenticationManager authenticationManager() throws Exception {
    return auth.getObject();
  }

  // Waffle configuration
  @Bean
  public Filter customPreAuthSecurityFilter() {
    return new CustomPreAuthSecurityFilter();
  }

  @Bean
  public Filter customNegotiateSecurityFilter() {
    return new CustomNegotiateSecurityFilter();
  }

  @Bean
  public WindowsAuthProviderImpl waffleAuthProvider(){
    return new WindowsAuthProviderImpl();
  }

  @Bean(name="negotiateSecurityFilterProvider")
  @Autowired
  public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(){
    NegotiateSecurityFilterProvider bean = new NegotiateSecurityFilterProvider(waffleAuthProvider());
    List<String> protocols = new ArrayList<>();
    protocols.add("Negotiate");
    bean.setProtocols(protocols);
    return bean;
  }

  @Bean
  public BasicSecurityFilterProvider basicSecurityFilterProvider(){
    return new BasicSecurityFilterProvider(waffleAuthProvider());
  }

  @Bean(name="waffleSecurityFilterProviderCollection")
  @Autowired
  public waffle.servlet.spi.SecurityFilterProviderCollection negotiateSecurityFilterProviderCollection() {
    final List<SecurityFilterProvider> lsp = new ArrayList<>();
    lsp.add(negotiateSecurityFilterProvider());
    lsp.add(basicSecurityFilterProvider());
    return new waffle.servlet.spi.SecurityFilterProviderCollection(lsp.toArray(new SecurityFilterProvider[]{}));
  }

  @Bean(name="negotiateSecurityFilterEntryPoint")
  @Autowired
  public waffle.spring.NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint() {
    final waffle.spring.NegotiateSecurityFilterEntryPoint ep = new waffle.spring.NegotiateSecurityFilterEntryPoint();
    ep.setProvider(negotiateSecurityFilterProviderCollection());
    return ep;
  }

  @Bean(name="negotiateSecurityFilter")
  @Autowired
  public waffle.spring.NegotiateSecurityFilter waffleNegotiateSecurityFilter(){
    waffle.spring.NegotiateSecurityFilter bean = new waffle.spring.NegotiateSecurityFilter();
    bean.setRoleFormat("both");
    bean.setPrincipalFormat("fqn");
    bean.setAllowGuestLogin(false);
    bean.setProvider(negotiateSecurityFilterProviderCollection());
    return bean;
  }

  // Static Mappings
  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/assets/**");
  }

  // Security filter chain
  // The custom filters can be removed if you only use waffle 
  // but this is how we added them
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // A user needs to have the role user and has to be authenticated
    http.exceptionHandling()
      .authenticationEntryPoint(negotiateSecurityFilterEntryPoint()).and()
      .addFilterBefore(customPreAuthSecurityFilter(), BasicAuthenticationFilter.class)
      .addFilterAfter(waffleNegotiateSecurityFilter(), BasicAuthenticationFilter.class)
      .addFilterAfter(customNegotiateSecurityFilter(), BasicAuthenticationFilter.class)
      .authorizeRequests().anyRequest().fullyAuthenticated();
     }
  }

Um den Waffel-AuthProvider automatisch verdrahten zu können, habe ich die folgende Wrapperklasse erstellt.

WindowsAuthenticationProviderWrapper.java

// ... imports 
// This class purpose is only to make the Windows authentication provider autowireable in spring.
@Component
public class WindowsAuthenticationProviderWrapper extends WindowsAuthenticationProvider{}

Wie gewünscht (Einige Codes wurden aufgrund von Sicherheitsrisiken entfernt).

CustomPreAuthFilter.java

import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * This filter removes the excess negoatiate header sent by IE. If the client
 * has already authenticated, strip the Authorization header from the request.
 */
public class CustomPreAuthSecurityFilter extends GenericFilterBean {
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    SecurityContext sec = SecurityContextHolder.getContext();
    HttpServletRequest req = (HttpServletRequest) servletRequest;

    if(sec != null && sec.getAuthentication() != null) {
      req = new CustomServletRequestWrapper(req);
    }

    try {
      filterChain.doFilter(req, servletResponse);
    } catch (RuntimeException e) {
      sendUnauthorized((HttpServletResponse) servletResponse);
    }
  }

  private void sendUnauthorized(HttpServletResponse response) throws IOException {
    logger.warn("error logging in user");
    SecurityContextHolder.clearContext();
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
  }
}

CustomNegotiateSecurityFilter.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;
import waffle.servlet.WindowsPrincipal;
import waffle.spring.WindowsAuthenticationToken;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * Handle post NTLM authentication against system database
 */
public class CustomNegotiateSecurityFilter extends GenericFilterBean {

  @Autowired
  private UserDAO userDAO;

  @Autowired
  Environment env;

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

  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    final HttpServletRequest request = (HttpServletRequest) req;
    final HttpServletResponse response = (HttpServletResponse) res;
    SecurityContext sec = SecurityContextHolder.getContext();
    Authentication authentication = sec.getAuthentication();

    // Continue filter chain if we are anonymously authenticated or if DB authentication has already happened.
    if (authentication != null && authentication.getClass() == WindowsAuthenticationToken.class) {

      // The user is Authenticated with NTLM but needs to be checked against the DB.
      User user;

      try {
        // fetch user from DB ...
      } catch (Exception e) {
        // The could not be found in the DB.
        sendUnauthorized(response);
        return;
      }

      // The user was found in the DB.
      WindowsPrincipal principal = (WindowsPrincipal)authentication.getPrincipal();
      final CustomAuthenticationToken token = new CustomAuthenticationToken(principal); // This class extends WindowsAuthenticationToken

      // add roles to token ...

      sec.setAuthentication(token);
    }

    chain.doFilter(request, response);
  }

  private void sendUnauthorized(HttpServletResponse response) throws IOException {
    logger.warn("Could not log in user");
    SecurityContextHolder.clearContext();
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
  }

  private void addRoleToAuthentication(WindowsAuthenticationToken authentication, String role) {
      for(GrantedAuthority authority : authentication.getAuthorities()) {
        if(authority.getAuthority().equals(role)) {
          return;
        }
      }
      authentication.getAuthorities().add(new SimpleGrantedAuthority(role));
  }
}

BEARBEITEN

Für diejenigen, die hier gefragt haben, ist eine Implementierung. CustomServletRequestWrapper:

class CustomServletRequestWrapper extends HttpServletRequestWrapper {


    public CustomServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    public String getHeader(String name) {
        if(name.equals("Authorization"))
            return null;
        String header = super.getHeader(name);
        return (header != null) ? header : super.getParameter(name); // Note: you can't use getParameterValues() here.
    }

    public Enumeration getHeaderNames() {
        List<String> names = Collections.list(super.getHeaderNames());

        names.addAll(Collections.list(super.getParameterNames()));
        names.remove("Authorization");
        return Collections.enumeration(names);
    }

}

Wenn Sie weitere Informationen benötigen, zögern Sie nicht zu fragen.

Verwandte Artikel


So iterieren Sie die Liste der Objekte im Frühjahr

Bhanu Krishnan: public class Members { private String fname; private String lname; public String getFname() { return fname; } public void setFname(String fname) { this.fname = fname; } public String getLn

So konfigurieren Sie netty im Frühjahr Boot 2

Lokesha S. Standardmäßig verwendet Spring Web Flux Netty, eine Ereignisschleife mit einem Thread. So konfigurieren Sie Spring Boot so, dass für jeden Kern ein Thread erstellt wird. Vielen Dank, Lokesh Brian Clozel Wie in der Spring Boot-Referenzdokumentation b

Konfigurieren der Konfigurationseigenschaften im Frühjahr

Konstantin Ich suche nach einer Möglichkeit, @ConfigurationPropertiesdie bei der Initialisierung definierten @Inject / @AutorwiredObjekte so zu bearbeiten, dass sie beim Konfigurieren des Objekts mithilfe einer @BeanMethode ordnungsgemäß konfiguriert werden. S