Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to wire in custom WebSecurityConfigurer in grails 5 #706

Open
ShurikAg opened this issue Jan 27, 2022 · 8 comments
Open

How to wire in custom WebSecurityConfigurer in grails 5 #706

ShurikAg opened this issue Jan 27, 2022 · 8 comments

Comments

@ShurikAg
Copy link

ShurikAg commented Jan 27, 2022

Issue description

I decided to post here, as I am not getting anything from the Stackoverflow post.

As part of moving our environments to Kubernetes, we are using Ambassador as the ingress service.
The app itself (the API side) is using Grails spring-security plugin. Having these two together, the preflight requests are not passing as the implementation will deny these requests. (see: https://www.getambassador.io/docs/edge-stack/latest/topics/using/cors/#authservice-and-cross-origin-resource-sharing).

I was digging for a solution for quite some time now, and the one that stands out in many places is to create a custom WebSecurityConfigurer (also, as suggested by Ambassador).

We I created the following:

package priz.api.security

import grails.compiler.GrailsCompileStatic
import org.springframework.boot.autoconfigure.security.SecurityProperties
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.CorsConfigurationSource

import javax.servlet.http.HttpServletRequest

@GrailsCompileStatic
@Configuration
@EnableWebSecurity
@Order(SecurityProperties.DEFAULT_FILTER_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {

    public void configure(final HttpSecurity http) throws Exception {
        http
                .cors().configurationSource(new PermissiveCorsConfigurationSource()).and()
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("**").permitAll();
    }

    private static class PermissiveCorsConfigurationSource implements CorsConfigurationSource {
        /**
         * Return a {@link CorsConfiguration} based on the incoming request.
         *
         * @param request
         * @return the associated {@link CorsConfiguration}, or {@code null} if none
         */
        @Override
        public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) {
            final CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowCredentials(true);
            configuration.setAllowedHeaders(Collections.singletonList("*"));
            configuration.setAllowedMethods(Collections.singletonList("*"));
            configuration.setAllowedOrigins(Collections.singletonList("*"));
            return configuration;
        }
    }
}

However, this config is not getting picked up. Is there anything additional that I have to do to register it? My expectation was that the annotations are taking care of that.
Also tried @EnableGlobalMethodSecurity instead, the same result.

Thanks for the advice.

I could also create an interceptor, but Grails interceptors cannot intercept the endpoints provided by the Spring Security core/rest plugins since the priority of their interceptors are higher than that of Grails interceptors

@codeconsole
Copy link
Contributor

codeconsole commented Jun 1, 2024

It won't get picked up unless you have @ComponentScan on your Application class.

@CompileStatic
@ComponentScan
class Application {

    static void main(String[] args) {
        Grails.run(Application, args)
    }
}

https://guides.grails.org/grails-configuration-properties/guide/index.html

@rainboyan
Copy link

In Grace, this is no longer needed, when the Application.groovy compiled, the @SpringBootApplication annotation will be added, just like Spring Boot does.

@codeconsole
Copy link
Contributor

@rainboyan in some cases developers might not want @ComponentScan or @EnableAutoConfiguration enabled by default with @SpringBootApplication. An alternative for the above configuration would be to enable it specifically:

@CompileStatic
@Import(SecurityConfig)
class Application {
    static void main(String[] args) {
        Grails.run(Application, args)
    }
}

@rainboyan
Copy link

@codeconsole
I don't quite understand what you said about the special case,
I can think of using @Import to load internal Configurations, or to test specific Configurations.
I prefer to use @Import on the *AutoConfiguration, instead of the main entry Application.
In the *AutoConfiguration classes, you can use @Conditional @AutoConfigureOrder @Order to constrain when the auto-configuration should apply.
In some case, if you find that specific auto-configuration classes that you do not want are being applied, you can use the exclude attribute of @SpringBootApplication to disable them, as shown in the following example:

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {

}

@codeconsole
Copy link
Contributor

codeconsole commented Jun 2, 2024

@rainboyan if you used @ComponentScan, it scans all your class files. @Import will just load the individual configuration. Using @Import is also more predictable behavior. Here we are only talking about loading a single Java Config. Using any other annotation might be overkill and end up with undesired behavior.

@codeconsole
Copy link
Contributor

codeconsole commented Jun 2, 2024

In Grace, this is no longer needed, when the Application.groovy compiled, the @SpringBootApplication annotation will be added, just like Spring Boot does.

@rainboyan using Grace 2023.0.0-M6 I created a sample app and still needed to add @Import in order to get the configuration to load.

@rainboyan
Copy link

@codeconsole
I have checkout your code to run, and I can confirm that you should register some OAuth2 clients and providers under the spring.security.oauth2.client prefix in the application.yml first, otherwise OAuth2ClientRegistrationRepositoryConfiguration won't be applied, that's what I said earlier about the benefits of using Spring Boot's AutoConfiguration.

---
spring:
    security:
        oauth2:
            client:
                registration:
                    github:
                        clientId: github-client-id
                        clientSecret: github-client-secret

https://docs.spring.io/spring-boot/reference/web/spring-security.html#web.security.oauth2

@codeconsole
Copy link
Contributor

codeconsole commented Jun 2, 2024

@rainboyan I have my registrations in application.properties (since they are private). That is why I have application.properties in .gitignore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants