2016-11-25 3 views
0

CAS WebSecurity를 ​​사용하는 스프링 부팅 응용 프로그램을 사용하여 들어오는 모든 인증되지 않은 요청을 공통 로그인 페이지로 리디렉션합니다.CAS를 우회하여 스프링 부팅 응용 프로그램에서 보안되지 않은 건강 정보를 얻습니다.

@Configuration 
@EnableWebSecurity 
public class CASWebSecurityConfig extends WebSecurityConfigurerAdapter { 

액츄에이터를 통해 헬스 엔드 포인트를 공개하고 관련 종속성을 추가하고 싶습니다. 나는 구성 방법에서, 그래서 내가 추가 한, 모니터링 도구로 사용하려고하는이/건강 URL의 CAS 검사를 우회하려는 :

http.authorizeRequests().antMatchers("/health/**").permitAll(); 

이 작동하지만, 지금은 더 그것을 조정할 싶어 :

  • 세부 건강 상태 (예 : 문서 당 "전체 콘텐츠")는 속성 파일에 자격 증명이 제공되는 특정 모니터링 사용자에게만 액세스 할 수 있어야합니다.
  • 인증이 제공되지 않으면 "상태 전용"을 반환해야합니다. 이 작업을해야 있도록

http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html#production-ready-health-access-restrictions 다음, 나는 다음과 같이 속성을 구성했습니다 http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html#production-ready-sensitive-endpoints 다음 ...

management.security.enabled: true 
endpoints.health.sensitive: false 

을하지만 나는 자격 증명을 구성하는 방법에 문제가, 내가 추가 내 설정 파일 :

security.user.name: admin 
security.user.password: secret 

그러나 그것은 작동하지 않습니다 - 내가 속성을 넣어하지 않을 때, 나는 로그에 생성 된 암호가 표시되지 않습니다. configureGlobal 방법은되도록

그래서 난 내 보안 설정에

healthcheck.username: healthCheckMonitoring 
healthcheck.password: healthPassword 

같은 일부 사용자 지정 속성을 넣고 다음을 주입하기 위해 노력하고있어 :

@Autowired 
public void configureGlobal(AuthenticationManagerBuilder auth, 
          CasAuthenticationProvider authenticationProvider) throws Exception { 

    auth.inMemoryAuthentication().withUser(healthcheckUsername).password(healthcheckPassword).roles("ADMIN"); 
    auth.authenticationProvider(authenticationProvider); 
} 

및 구성 방법에, 나는 변경 URL 패턴의 구성은 다음과 같습니다.

http.authorizeRequests() 
     .antMatchers("/health/**").hasAnyRole("ADMIN") 
     .and().httpBasic() 
     .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
     .and().csrf().disable(); 

설정을 사용하면 내용이 인증 될 때 논리적이지만 인증되지 않으면 요청이 끝 점에 도달하지 않기 때문에 논리적으로 상태 (UP 또는 DOWN)를 얻지 못합니다. 보안 구성에 의해 차단되고 거부됩니다.

제대로 작동하려면 스프링 보안 설정을 조정할 수 있습니까? 나는 어떻게 든 configs를 연결해야만한다는 느낌이 들었습니다. CAS 구성은 먼저 URL을 기반으로하는 요청을 허용하므로 자격 증명이 제공되면 요청이 기본 http 인증을 수행하는 두 번째 구성에 도달하게하거나 요청은 "상태 전용"결과를 얻을 수 있도록 인증되지 않은 엔드 포인트에 충돌합니다. 그러나 동시에, 올바르게 구성하면 스프링 부트가 올바르게 관리 할 수 ​​있다고 생각합니다.

감사합니다!

답변

0

해결이 잘되지 않습니다 만, 지금까지, 그것은 나를 위해 작동 내용은 다음과 같습니다

내 설정 (단지 관련 코드)에

가 :

:
@Configuration 
@EnableWebSecurity 
public class CASWebSecurityConfig extends WebSecurityConfigurerAdapter { 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    //disable HTTP Session management 
    http 
     .securityContext() 
     .securityContextRepository(new NullSecurityContextRepository()) 
     .and() 
     .sessionManagement().disable(); 

    http.requestCache().requestCache(new NullRequestCache()); 

    //no security checks for health checks 
    http.authorizeRequests().antMatchers("/health/**").permitAll(); 

    http.csrf().disable(); 

    http 
     .exceptionHandling() 
     .authenticationEntryPoint(authenticationEntryPoint()); 

    http // login configuration 
     .addFilter(authenticationFilter()) 
     .authorizeRequests().anyRequest().authenticated(); 
} 
} 

가 그럼 난 특정 필터를 추가
@Component 
public class HealthcheckSimpleStatusFilter extends GenericFilterBean { 

private final String AUTHORIZATION_HEADER_NAME="Authorization"; 

private final String URL_PATH = "/health"; 

@Value("${healthcheck.username}") 
private String username; 

@Value("${healthcheck.password}") 
private String password; 

private String healthcheckRole="ADMIN"; 

@Override 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
    throws IOException, ServletException { 
    HttpServletRequest httpRequest = this.getAsHttpRequest(request); 

    //doing it only for /health endpoint. 
    if(URL_PATH.equals(httpRequest.getServletPath())) { 

     String authHeader = httpRequest.getHeader(AUTHORIZATION_HEADER_NAME); 

     if (authHeader != null && authHeader.startsWith("Basic ")) { 
      String[] tokens = extractAndDecodeHeader(authHeader); 
      if (tokens != null && tokens.length == 2 && username.equals(tokens[0]) && password.equals(tokens[1])) { 
       createUserContext(username, password, healthcheckRole, httpRequest); 
      } else { 
       throw new BadCredentialsException("Invalid credentials"); 
      } 
     } 
    } 
    chain.doFilter(request, response); 
} 

/** 
* setting the authenticated user in Spring context so that {@link HealthMvcEndpoint} knows later on that this is an authorized user 
* @param username 
* @param password 
* @param role 
* @param httpRequest 
*/ 
private void createUserContext(String username, String password, String role,HttpServletRequest httpRequest) { 
    List<GrantedAuthority> authoritiesForAnonymous = new ArrayList<>(); 
    authoritiesForAnonymous.add(new SimpleGrantedAuthority("ROLE_" + role)); 
    UserDetails userDetails = new User(username, password, authoritiesForAnonymous); 
    UsernamePasswordAuthenticationToken authentication = 
     new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); 
    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest)); 
    SecurityContextHolder.getContext().setAuthentication(authentication); 
} 

private HttpServletRequest getAsHttpRequest(ServletRequest request) throws ServletException { 
    if (!(request instanceof HttpServletRequest)) { 
     throw new ServletException("Expecting an HTTP request"); 
    } 
    return (HttpServletRequest) request; 
} 

private String[] extractAndDecodeHeader(String header) throws IOException { 
    byte[] base64Token = header.substring(6).getBytes("UTF-8"); 

    byte[] decoded; 
    try { 
     decoded = Base64.decode(base64Token); 
    } catch (IllegalArgumentException var7) { 
     throw new BadCredentialsException("Failed to decode basic authentication token",var7); 
    } 

    String token = new String(decoded, "UTF-8"); 
    int delim = token.indexOf(":"); 
    if(delim == -1) { 
     throw new BadCredentialsException("Invalid basic authentication token"); 
    } else { 
     return new String[]{token.substring(0, delim), token.substring(delim + 1)}; 
    } 
} 

}