Spring Security OAuth2: multiple ResourceServerConfiguration not working - spring-boot

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.

Related

Spring Security does not intercept requests

I have a legacy application in which I have added Spring Web MVC libraries in order to expose a new Rest API.
I am struggling integrating spring-security in order to intercept the incoming requests. I have set up a security configuration class
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
and a security application initializer
public class SecurityWebApplicationInitializer extends
AbstractSecurityWebApplicationInitializer {
}
following relevant guides.
Using debugger I verified that during initializing my configuration class is loaded. My problem is that my requests are not intercepted as expected.
Since you're already using Spring MVC, go to your class that initializes your application. If you're using Java Config, it most likely extends AbstractAnnotationConfigDispatcherServletInitializer.
Add your SecurityConfig to its "root config classes":
public class MySpringMmvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected abstract Class<?>[] getRootConfigClasses() {
return new Class[] { ..., SecurityConfig.class};
}
}
I think you forgot the #configuration annotation, try this
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}

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

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

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).

Global method security in Spring Boot

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 {
...
}

Resources