apply Spring's actuator

This commit is contained in:
anhefti 2019-05-09 11:26:11 +02:00
parent 5032e39352
commit e2b93e5529
5 changed files with 74 additions and 14 deletions

View file

@ -32,7 +32,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpHeaders;
import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory;
@ -45,7 +45,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.filter.CharacterEncodingFilter;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.profile.DevGuiProfile; import ch.ethz.seb.sebserver.gbl.profile.DevGuiProfile;
import ch.ethz.seb.sebserver.gbl.profile.DevWebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.DevWebServiceProfile;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@ -59,13 +58,13 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@WebServiceProfile @WebServiceProfile
@GuiProfile @GuiProfile
@RestController @RestController
@Order(6) @Order(7)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ErrorController { public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ErrorController {
private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class); private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);
@Value("${sebserver.webservice.api.admin.endpoint}") // @Value("${sebserver.webservice.api.admin.endpoint}")
private String adminEndpoint; // private String adminEndpoint;
@Value("${sebserver.webservice.api.redirect.unauthorized}") @Value("${sebserver.webservice.api.redirect.unauthorized}")
private String unauthorizedRedirect; private String unauthorizedRedirect;
@ -101,13 +100,16 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
web web
.ignoring() .ignoring()
.antMatchers("/error") .antMatchers("/error")
.antMatchers(this.adminEndpoint + API.INFO_ENDPOINT + "/**"); // TODO this may not be necessary, test with separated GUI and webservice server
//.antMatchers(this.adminEndpoint + API.INFO_ENDPOINT + "/**")
;
} }
@RequestMapping("/error") @RequestMapping("/error")
public void handleError(final HttpServletResponse response) throws IOException { public void handleError(final HttpServletResponse response) throws IOException {
response.setStatus(HttpStatus.NOT_FOUND.value()); response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.sendRedirect(this.unauthorizedRedirect); response.setHeader(HttpHeaders.LOCATION, this.unauthorizedRedirect);
response.flushBuffer();
} }
@Override @Override
@ -123,7 +125,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
@DevGuiProfile @DevGuiProfile
@DevWebServiceProfile @DevWebServiceProfile
public ClientHttpRequestFactory clientHttpRequestFactory() { public ClientHttpRequestFactory clientHttpRequestFactory() {
log.info("Initialize with insecure ClientHttpRequestFactory for development"); log.info("Initialize with insecure ClientHttpRequestFactory for development");
return new DevClientHttpRequestFactory(); return new DevClientHttpRequestFactory();
} }

View file

@ -23,7 +23,7 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@Configuration @Configuration
@GuiProfile @GuiProfile
@Order(4) @Order(5)
public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter { public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired @Autowired

View file

@ -24,7 +24,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@ -43,6 +43,7 @@ import org.springframework.security.oauth2.provider.token.UserAuthenticationConv
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import ch.ethz.seb.sebserver.WebSecurityConfig; import ch.ethz.seb.sebserver.WebSecurityConfig;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebClientDetailsService; import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebClientDetailsService;
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebserviceResourceConfiguration; import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebserviceResourceConfiguration;
@ -64,9 +65,8 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebserviceResourceConfigu
* and is by default set to "/exam-api/**" */ * and is by default set to "/exam-api/**" */
@WebServiceProfile @WebServiceProfile
@Configuration @Configuration
//@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity @EnableWebSecurity
@Order(5) @Order(6)
@Import(DataSourceAutoConfiguration.class) @Import(DataSourceAutoConfiguration.class)
public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter { public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
@ -89,6 +89,8 @@ public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
private String adminAPIEndpoint; private String adminAPIEndpoint;
@Value("${sebserver.webservice.api.exam.endpoint}") @Value("${sebserver.webservice.api.exam.endpoint}")
private String examAPIEndpoint; private String examAPIEndpoint;
@Value("${management.endpoints.web.base-path}")
private String actuatorEndpoint;
@Value("${sebserver.webservice.api.redirect.unauthorized}") @Value("${sebserver.webservice.api.redirect.unauthorized}")
private String unauthorizedRedirect; private String unauthorizedRedirect;
@ -154,6 +156,16 @@ public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
this.examAPIEndpoint); this.examAPIEndpoint);
} }
@Bean
protected ResourceServerConfiguration sebServerActuatorResources() throws Exception {
return new ActuatorResourceServerConfiguration(
this.tokenStore,
this.webServiceClientDetails,
authenticationManagerBean(),
this.actuatorEndpoint,
this.unauthorizedRedirect);
}
// NOTE: We need two different class types here to support Spring configuration for different // NOTE: We need two different class types here to support Spring configuration for different
// ResourceServerConfiguration. There is a class type now for the Admin API as well as for the Exam API // ResourceServerConfiguration. There is a class type now for the Admin API as well as for the Exam API
private static final class AdminAPIResourceServerConfiguration extends WebserviceResourceConfiguration { private static final class AdminAPIResourceServerConfiguration extends WebserviceResourceConfiguration {
@ -191,6 +203,7 @@ public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
tokenStore, tokenStore,
webServiceClientDetails, webServiceClientDetails,
authenticationManager, authenticationManager,
// TODO create a proper error handling here with also documentation on SEB Binding Specification
(request, response, exception) -> { (request, response, exception) -> {
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
@ -205,6 +218,36 @@ public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
} }
} }
private static final class ActuatorResourceServerConfiguration extends WebserviceResourceConfiguration {
public ActuatorResourceServerConfiguration(
final TokenStore tokenStore,
final WebClientDetailsService webServiceClientDetails,
final AuthenticationManager authenticationManager,
final String apiEndpoint,
final String redirect) {
super(
tokenStore,
webServiceClientDetails,
authenticationManager,
new LoginRedirectOnUnauthorized(redirect),
ADMIN_API_RESOURCE_ID,
apiEndpoint,
true,
4);
}
@Override
protected void addConfiguration(final String apiEndpoint, final HttpSecurity http) throws Exception {
http.antMatcher(apiEndpoint + "/**")
.authorizeRequests()
.anyRequest()
.hasAuthority(UserRole.SEB_SERVER_ADMIN.name());
}
}
private static class LoginRedirectOnUnauthorized implements AuthenticationEntryPoint { private static class LoginRedirectOnUnauthorized implements AuthenticationEntryPoint {
private final String redirect; private final String redirect;
@ -222,8 +265,9 @@ public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
log.warn("Unauthorized Request: {} : Redirect to login after unauthorized request", log.warn("Unauthorized Request: {} : Redirect to login after unauthorized request",
request.getRequestURI()); request.getRequestURI());
response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.sendRedirect(this.redirect); response.setHeader(HttpHeaders.LOCATION, this.redirect);
response.flushBuffer();
} }
} }

View file

@ -43,6 +43,7 @@ public abstract class WebserviceResourceConfiguration extends ResourceServerConf
super(); super();
final ConfigurerAdapter configurerAdapter = new ConfigurerAdapter( final ConfigurerAdapter configurerAdapter = new ConfigurerAdapter(
this,
tokenStore, tokenStore,
webServiceClientDetails, webServiceClientDetails,
authenticationManager, authenticationManager,
@ -61,8 +62,13 @@ public abstract class WebserviceResourceConfiguration extends ResourceServerConf
super.setConfigurers(configurers); super.setConfigurers(configurers);
} }
protected void addConfiguration(final String apiEndpoint, final HttpSecurity http) throws Exception {
// To override of additional configuration is needed
}
private static final class ConfigurerAdapter extends ResourceServerConfigurerAdapter { private static final class ConfigurerAdapter extends ResourceServerConfigurerAdapter {
private final WebserviceResourceConfiguration webserviceResourceConfiguration;
private final TokenStore tokenStore; private final TokenStore tokenStore;
private final WebClientDetailsService webServiceClientDetails; private final WebClientDetailsService webServiceClientDetails;
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
@ -72,6 +78,7 @@ public abstract class WebserviceResourceConfiguration extends ResourceServerConf
private final boolean supportRefreshToken; private final boolean supportRefreshToken;
public ConfigurerAdapter( public ConfigurerAdapter(
final WebserviceResourceConfiguration webserviceResourceConfiguration,
final TokenStore tokenStore, final TokenStore tokenStore,
final WebClientDetailsService webServiceClientDetails, final WebClientDetailsService webServiceClientDetails,
final AuthenticationManager authenticationManager, final AuthenticationManager authenticationManager,
@ -81,6 +88,7 @@ public abstract class WebserviceResourceConfiguration extends ResourceServerConf
final boolean supportRefreshToken) { final boolean supportRefreshToken) {
super(); super();
this.webserviceResourceConfiguration = webserviceResourceConfiguration;
this.tokenStore = tokenStore; this.tokenStore = tokenStore;
this.webServiceClientDetails = webServiceClientDetails; this.webServiceClientDetails = webServiceClientDetails;
this.authenticationManager = authenticationManager; this.authenticationManager = authenticationManager;
@ -121,6 +129,8 @@ public abstract class WebserviceResourceConfiguration extends ResourceServerConf
.headers().frameOptions().disable() .headers().frameOptions().disable()
.and() .and()
.csrf().disable(); .csrf().disable();
this.webserviceResourceConfiguration.addConfiguration(this.apiEndpoint, http);
} }
} }

View file

@ -17,5 +17,7 @@ sebserver.webservice.api.exam.endpoint=/exam-api/v1
sebserver.webservice.api.exam.accessTokenValiditySeconds=1800 sebserver.webservice.api.exam.accessTokenValiditySeconds=1800
sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1 sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1
management.endpoints.web.base-path=/actuator
sebserver.webservice.api.pagination.maxPageSize=500 sebserver.webservice.api.pagination.maxPageSize=500