2016-04-28 23 views
8

Starałem się uzyskać gofr do pracy z wiosną 4.2.5 przy użyciu konfiguracji wiosna java. Pomyślałem, że równie dobrze mogę pomóc innym w tej samej sytuacji.Jak skonfigurować gofrowaną wiosnę przy użyciu konfiguracji java

Używamy niestandardowego filtru prewaffle i postwaffle do uwierzytelnienia, że ​​użytkownik istnieje w naszej bazie danych po sprawdzeniu poprawności protokołu NTLM wafli.

Mamy również metody autoryzacji działań użytkownika przy użyciu adnotacji EnableGlobalMethodSecurity.

Aby to zadziałało wiosną konfiguracja Java była kłopotliwa. Nasze rozwiązanie znajdziesz w odpowiedzi poniżej. Mam nadzieję, że to pomoże.

Odpowiedz

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

Aby móc autowire Gofrownica authProvider stworzyłem następujące wrapperclass.

WindowsAuthenticationProviderWrapper.java

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

Zgodnie z wnioskiem (Niektóre kod został pozbawiony z powodu zagrożenia bezpieczeństwa).

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

EDIT

Dla tych, którzy pytali o tutaj jest jedna realizacja. 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); 
    } 

} 

Jeśli potrzebujesz więcej informacji, nie wahaj się zapytać.

+0

Próbuję zaimplementować Twój kod, ale otrzymuję: Fabryczna metoda "springSecurityFilterChain" rzucił wyjątek; Zagnieżdżony wyjątek to org.springframework.security.config.annotation.AlreadyBuiltException: Ten obiekt został już zbudowany. – naoru

+0

Nie mam już dostępu do bazy kodu, więc nie mogę sprawdzić. Pamiętam, że miałem podobne problemy. Chyba dlatego, że już stworzyłeś obiekt. Sprawdź, dlaczego jest tworzony dwa razy. Jeśli znajdziesz jakieś błędy, zgłoś je tutaj. –

+0

@PabloJomer - Dziękuję za odpowiedź. Jednak otrzymuję "waffle.spring.NegotiateSecurityFilter: pomyślnie zalogowany użytkownik: domena \ nazwa użytkownika" i "waffle.spring.NegotiateSecurityFilter: rejestracja błędu w user: com.sun.jna.platform.win32.Win32Exception: token dostarczony do funkcja jest nieprawidłowa "za pierwszym razem, gdy próbuję. Odświeżanie przeglądarki po działa poprawnie. – JHS