2016-04-28 63 views
8

我一直在努力使用spring java配置让华夫饼干与spring 4.2.5一起工作。我想我可能也会在同样的情况下帮助别人。如何使用java配置在弹簧中配置华夫饼干

我们使用一个自定义preWaffle和postWaffle过滤器来验证用户是否存在于我们的数据库中,通过waffles NTLM协议进行了验证。

我们还有使用EnableGlobalMethodSecurity注释授权用户操作的方法。

为了在spring的java配置中使用这个工作是麻烦的一件事,至少可以这样说。您可以在下面的答案中找到我们的解决方案。我希望这会有所帮助。

回答

8

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(); 
    } 
    } 

为了能够自动装配我创建了以下wrapperclass松饼authProvider。

WindowsAuthenticationProviderWrapper.java

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

按照要求(有些代码已经被剥离,由于安全隐患)。

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

编辑

对于那些谁问这里是一个实现。 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); 
    } 

} 

如果您需要更多信息请不要犹豫,问问。

+0

我试图实现你的代码,但我得到:工厂方法'springSecurityFilterChain'抛出异常;嵌套的异常是org.springframework.security.config.annotation.AlreadyBuiltException:这个对象已经建好了 – naoru

+0

我没有权限访问代码库,所以我无法检查。我记得有一些类似的问题。我想这是因为你已经创建了这个对象。检查为什么它被创建两次,如果你发现任何缺陷,请在这里报告。 –

+0

@PabloJomer - 谢谢你的回答。但是,我得到“waffle.spring.NegotiateSecurityFilter:成功登录用户:域\用户名”和“waffle.spring.NegotiateSecurityFilter:错误登录用户:com.sun.jna.platform.win32.Win32Exception:提供给功能无效“我第一次尝试。浏览器刷新后工作正常。 – JHS