Global method security in Spring Boot - spring

I'm having some issues when trying to enable the global method security in a Spring Boot application.
More or less I've this configuration:
#ComponentScan
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(Main.class);
app.setShowBanner(false);
ApplicationContext context = app.run(args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Main.class);
}
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, proxyTargetClass = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
...
}
#Override
protected void configure(HttpSecurity http) throws Exception {
...
}
}
#Controller
public class SampleController {
#RequestMapping("/api/hello")
#ResponseBody
String hello() {
return "Hello!";
}
#Secured(SecurityGrant.WRITE_PROJECT)
#RequestMapping("/api/bye")
#ResponseBody
String bye() {
return "Bye!";
}
}
The #Secure annotations are working OK at services, but not in controllers, so as I read here (http://docs.spring.io/spring-security/site/faq/faq.html#faq-method-security-in-web-context) I think is because method security is only configured in the root application context and not in the one for the servlet.
However, I can't find the way to set this via Java Configuration, instead of using a web.xml file.
Any ideas?
Update:
As pointed in the comments, methods should be public to be proxied.

The controller methods need to be public in order to be proxied for #Secured. Just doing that should fix it.

In XML you would have to define a second global-method-security in the servlet-context.xml file. This is because there are two contexts, the root context and the web context and security needs to be configured in each separately.
In Java config, try to create a separate web configuration class, and mark it with #EnableWebMvc:
#Configuration
#EnableWebMvc
#EnableGlobalMethodSecurity(securedEnabled = true, proxyTargetClass = true)
public class WebConfig {
...
}

Related

PrincipalExtractor and AuthoritiesExtractor doesn't hit

I have a project with Spring security and Oauth2.
On the resource server I have the following configuration:
#Configuration
public class SecurityConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests().antMatchers("/info", "/health", "/h2-console/**").permitAll()
.anyRequest().authenticated()
.and().headers().frameOptions().disable();
}
}
I have the following extractors:
#Component
public class InsurancePrincipalExtractor implements PrincipalExtractor {
#Override
public Object extractPrincipal(Map<String, Object> map) {
return map.get("username");
}
}
#Component
public class InsuranceAuthoritiesExtractor implements AuthoritiesExtractor {
#Override
public List<GrantedAuthority> extractAuthorities(Map<String, Object> map) {
//Logic
}
I set the user-info-uri: http://localhost:8081/uaa/v1/me
The problem is that it does not hit my extractor methods at runtime, so nothing happens. As I know I just need to annotate it with the #Component and the Spring boot and will use it auto.
UPDATE:
Solution founded.
I had to add this to my configuration as well:
#Bean
protected ResourceServerTokenServices resourceServerTokenServices(ResourceServerProperties sso,
OAuth2ClientContext oauth2ClientContext,
UserInfoRestTemplateFactory restTemplateFactory) {
UserInfoTokenServices services = new UserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
services.setRestTemplate(restTemplateFactory.getUserInfoRestTemplate());
services.setTokenType(sso.getTokenType());
return services;
}

Spring Security OAuth2: multiple ResourceServerConfiguration not working

Spring boot version: 1.5.8.RELEASE
Spring cloud version: Edgware.RELEASE (using zuul)
Trying to configure multiple resources and, following this example in github, can't make it work.
My code is:
class ResourceServerConfigurationFactory
{
static ResourceServerConfiguration criarResourceServerConfiguration(String resourceId, int order,
HttpSecurityConfigurer configurer)
{
ResourceServerConfiguration resource = new ResourceServerConfiguration()
{
// Switch off the Spring Boot #Autowired configurers
public void setConfigurers(List<ResourceServerConfigurer> configurers)
{
super.setConfigurers(configurers);
}
};
resource.setConfigurers(Arrays.<ResourceServerConfigurer>asList(new ResourceServerConfigurerAdapter()
{
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
{
resources.resourceId(resourceId);
}
#Override
public void configure(HttpSecurity http) throws Exception
{
configurer.configure(http);
}
}));
resource.setOrder(order);
return resource;
}
}
interface HttpSecurityConfigurer
{
public void configure(HttpSecurity http) throws Exception;
}
And my configuration:
#Configuration
public class OAuthResourceConfiguration
{
#Bean
protected ResourceServerConfiguration usuarioResources()
{
return ResourceServerConfigurationFactory.criarResourceServerConfiguration("usuario", -10,
http -> http.antMatcher("/user").authorizeRequests().anyRequest().permitAll());
}
#Bean
protected ResourceServerConfiguration funcaoResources()
{
return ResourceServerConfigurationFactory.criarResourceServerConfiguration("funcao", -20,
http -> http.antMatcher("/ws").authorizeRequests().anyRequest().permitAll());
}
}
Finally, the Spring boot application:
#SpringBootApplication
#EnableResourceServer
#EnableZuulProxy
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
Facts:
Spring instantiates both ResourceServerConfiguration beans;
Only the bean with higher order works (/user endpoint is ok, /ws endpoint keeps asking authentication)
In spring log, I can see that only /user ant matcher is used. /ws gets completely ignored.
What's wrong?
The problem was related to the Factory class I created.
The combination of lambda + anonymous class created some kind of problem (that I was not able to understand) that screwed up things.
Declaring both Configurers as Beans in the #Configuration class resolved the problem.

Diffrent way of implementation security ends with the same error

I have implemented an application with combination Spring Boot and Angular 4. I put all Angular files under /resources/static directory:
static directory
Then I added to Spring Security classes:
#Configuration
#EnableWebMvc
#ComponentScan("com.inventory")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/static/**")
.addResourceLocations("classpath:/resources/static/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index.html");
}
}
and:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated();
}
and it seem that everythings should work. Unfortunately whenever I run my app it throws exception:
There was an unexpected error (type=Internal Server Error, status=500).
Could not resolve view with name 'index.html' in servlet with name 'dispatcherServlet'.
Of course I tried diffrent solution like adding this:
#Controller
public class ViewController {
#RequestMapping(value = "/#/")
public String index() {
return "forward:/index.html";
}
#RequestMapping(value = "/")
public String home() {
return "forward:/index.html";
}
}
But nothing works. Does anyone has a clue what else can I do?
When using Spring boot normally you don't have to configure resource handler manually, spring boot will automatically load contents from the following loc:
/static
/public
/resources
/META-INF/resources
see spring boot guides on loading static contents

Spring Security Filter showing not found despite being defined in Java config

I have configured my Spring application using Java based config. When I start my application, I get the error NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined. I have defined all the configuration classes but this error still occurs. How do I fix this?
My main class:
public class SiteMain implements WebApplicationInitializer {
private void initSpringMvcServlet(ServletContext container) {
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(MvcConfig.class);
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private void initSpringRootContext(ServletContext container) {
XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
rootContext.setConfigLocation("/WEB-INF/site.xml");
container.addListener(new ContextLoaderListener(rootContext));
}
#Override
public void onStartup(ServletContext container) throws ServletException {
initSpringRootContext(container);
initSpringMvcServlet(container);
}
}
My Security Initializer class is:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { }
My MVC Config class is:
#Configuration
#EnableWebMvc
#ComponentScan
#Import(SecurityConfig.class)
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/").setCachePeriod(31556926);
}
}
My Security Config class is:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**").permitAll().anyRequest().authenticated()
.and().formLogin().loginPage("/").permitAll()
.and().logout().permitAll()
.and().rememberMe();
}
}
Try replacing this line:
dispatcherContext.register(MvcConfig.class);
with:
dispatcherContext.setConfigLocation("your.config.package");
add line below:
container.addListener(new ContextLoaderListener(dispatcherContext));
There is no need to #Import(SecurityConfig) since setConfigLocation will automatically detect all #Configuration annotated classes.

At least one mapping is required erro in Spring

Here's a problem: I would like to protect a URI until authorized with some third-party OAuth2. Based on http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configuration/EnableOAuth2Client.html, I have these:
#Configuration
#EnableOAuth2Client
public class OAuth2Client extends OAuth2ClientConfiguration {
#Bean
public Filter filter() {
DelegatingFilterProxy f = new DelegatingFilterProxy();
f.setTargetBeanName("oauth2ClientContextFilter");
return f;
}
#Resource
#Qualifier("oauth2ClientContextFilter")
private OAuth2ClientContextFilter oauth2ClientContextFilter;
#Resource
#Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;
#Bean
public OAuth2ProtectedResourceDetails remote() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setUserAuthorizationUri("http://localhost2/oauth/authorize");
return details;
}
#Bean
public OAuth2RestOperations restTemplate() {
return new OAuth2RestTemplate(remote(), new DefaultOAuth2ClientContext(
accessTokenRequest));
}
}
And
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
// Empty for now...
}
And finally
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
super.configure(auth);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/protectedUri").and()
.authorizeRequests().requestMatchers()
.hasRole("#oauth2.hasScope('read')");
}
}
But this gives:
java.lang.IllegalStateException: At least one mapping is required
(i.e. authorizeRequests().anyRequest.authenticated())
I've tried quite a few combinations of the HttpSecurity builder to no avail - any help, or is this approach entirely off base?
is this approach entirely off base?
Yes. An empty ResourceServerConfigurerAdapter isn't going to help you. You should configure the protected paths, e.g.
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/protectedUri").authenticated();
}
(and leave out your WebSecurityConfigurerAdapter).
The client configuration at the top looks wrong too, but it's not relevant to the protected resource (start a new question if you want to know how to configure the client).

Resources