package com.sequenceiq.periscope.config;
import static com.sequenceiq.periscope.api.AutoscaleApi.API_ROOT_CONTEXT;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.web.filter.OncePerRequestFilter;
import com.sequenceiq.periscope.domain.PeriscopeUser;
import com.sequenceiq.periscope.service.security.OwnerBasedPermissionEvaluator;
import com.sequenceiq.periscope.service.security.UserDetailsService;
import com.sequenceiq.periscope.service.security.UserFilterField;
@Configuration
public class SecurityConfig {
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Inject
private OwnerBasedPermissionEvaluator ownerBasedPermissionEvaluator;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
OAuth2MethodSecurityExpressionHandler expressionHandler = new OAuth2MethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(ownerBasedPermissionEvaluator);
return expressionHandler;
}
}
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Value("${periscope.client.id}")
private String clientId;
@Value("${periscope.client.secret}")
private String clientSecret;
@Autowired
@Qualifier("identityServerUrl")
private String identityServerUrl;
@Autowired
private UserDetailsService userDetailsService;
@Bean
RemoteTokenServices remoteTokenServices() {
RemoteTokenServices rts = new RemoteTokenServices();
rts.setClientId(clientId);
rts.setClientSecret(clientSecret);
rts.setCheckTokenEndpointUrl(identityServerUrl + "/check_token");
return rts;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("periscope");
resources.tokenServices(remoteTokenServices());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(new ScimAccountGroupReaderFilter(userDetailsService), AbstractPreAuthenticatedProcessingFilter.class)
.authorizeRequests()
.antMatchers(API_ROOT_CONTEXT + "/clusters/**").access("#oauth2.hasScope('cloudbreak.stacks') and #oauth2.hasScope('periscope.cluster')")
.antMatchers(API_ROOT_CONTEXT + "/swagger.json").permitAll()
.antMatchers(API_ROOT_CONTEXT + "/api-docs/**").permitAll()
.antMatchers(API_ROOT_CONTEXT + "/**").denyAll()
.and()
.csrf()
.disable()
.headers()
.contentTypeOptions();
}
}
private static class ScimAccountGroupReaderFilter extends OncePerRequestFilter {
private UserDetailsService userDetailsService;
ScimAccountGroupReaderFilter(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@SuppressWarnings("unchecked")
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException,
IOException {
if (SecurityContextHolder.getContext().getAuthentication() != null) {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
PeriscopeUser user = userDetailsService.getDetails(username, UserFilterField.USERNAME);
request.setAttribute("user", user);
}
filterChain.doFilter(request, response);
}
}
}