oauth2 and basic auth - spring-boot

I use spring boot 2.4.6 with spring security.
Actually we use oauth 2
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues())
.and() // (1)
.authorizeRequests()
.antMatchers("/actuator/**").permitAll()
.antMatchers("/v2/api-docs").permitAll()
.anyRequest().authenticated() // (2)
.and()
.oauth2ResourceServer().jwt() // (3)
.jwtAuthenticationConverter(jwtAuthenticationConverter());
}
}
For some endpoint, I need to support a login / password.
Is there a way to do that?

You can set up multiple HttpSecurity instances, each matching one or more paths and implementing different authentication schemes. You can add them as separate inner classes extending from WebSecurityConfigurerAdapter. See docs for more information and an example.
Make sure to include an #Order if order matters. In your provided example, the config is generic and matches all requests, so it should be #Order(2). The additional config would be #Order(1) and start with http.antMatcher("/some/path/**").formLogin()... or similar.
Note: Similar (older) questions here and here.

Related

Why is OAuth2UserService not running for role authorization in Spring Boot under WebSecurityConfigurerAdapter?

I am trying to implement roles with Spring Security by following Spring Security's documentation, but I haven't been able to run the OAuth2UserService.
This is the configuration file that I have and OAuth2UserService, which is following their documentation. The terminal prints ABC, but not DEF so it's not running when I go to the page "/test" as an example. I'm using Google Identity with OAuth2.
The authentication works, but unfortunately this doesn't. I've tried using GrantedAuthoritesMapper and a number of other examples as well, but the same thing happens.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout(l -> {
l.logoutSuccessUrl("/").permitAll();})
.authorizeRequests(a -> a
.antMatchers("/", "/js/**", "/css/**").permitAll()
.antMatchers("/test").hasRole("ADMIN")
.anyRequest().authenticated()
)
.csrf(c -> c
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo
.userService(this.oauth2UserService()
))
);
}
private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
final DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
System.out.println("ABC");
return (userRequest) -> {
System.out.println("DEF");
OAuth2User oauth2User = delegate.loadUser(userRequest);
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
oauth2User = new DefaultOAuth2User(mappedAuthorities,
oauth2User.getAttributes(), oauth2User.getName());
return oauth2User;
};
}
Any help would be much appreciated. Thank you.
If you haven't found the answer yet, my problem was solved by adding the scope to application.properties file.
spring.security.oauth2.client.registration.google.scope=profile,email

How to allow CrossOrigin from all domains?

Is there anyway to make this end point allow request from anywhere?
I've tried like but none of them worked.
#CrossOrigin(origins = "")
#CrossOrigin(origins = "http://")
#CrossOrigin(origins = "http://localhost:3001")
#GetMapping(path="/transactions")
public #ResponseBody List<RealEstateTransaction> getTransactions() {
return realEstateTransactionService.findTargets();
}
While working with cross domains, most of the time we tend to worry about what & where it went wrong. There are many factors including security, web components, sockets, etc to be handled at the server side before a request is processed. Many ways to implement the CORS in the Spring Boot application.
1. Annotation
By implementing #CrossOrigin like what you did in the Main class. Also can be done by adding #CrossOrigin to specific controllers/methods, if particular API should be accessed only from specific domain.
#CrossOrigin("*") // to allow from all domains
#CrossOrigin("http://localhost:3001") // to allow from specific domain
#CrossOrigin(origins = "http://localhost:3001")
2. WebConfig
If Spring Application is MVC where the resources could be accessed. Simply add the CORS mappings by overriding WebMvcConfigurer's addCorsMappings function.
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*");
}
}
3. SecurityConfig
When security is enabled in the application then CORS must be implementated in the SecurityConfig. Registering the CORS filter can be done in many ways. One is adding UrlBasedCorsConfigurationSource to the http.cors() function. Another is to create CustomCorsFilter by extending the CorsFilter.
public class CustomCorsFilter extends CorsFilter {
public CustomCorsFilter() {
super(configurationSource());
}
public static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", configuration);
return corsConfigurationSource;
}
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] paths = {"/auth/**", "/env"};
//http.cors().configurationSource(CustomCorsFilter.configurationSource()); // Option 1
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(this.authenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers(paths)
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/**")
.authenticated()
.and()
.addFilterBefore(new CustomCorsFilter(), UsernamePasswordAuthenticationFilter.class); //option 2
}

How to turn off Spring Security in Spring Boot Application

I have implemented authentication in my Spring Boot Application with Spring Security.
The main class controlling authentication should be websecurityconfig:
#Configuration
#EnableWebSecurity
#PropertySource(value = { "classpath:/config/application.properties" })
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(
SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/ristore/**").authenticated()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(new SimpleUrlAuthenticationFailureHandler());
}
Since I am doing OAuth, I have AuthServerConfig and ResourceServerConfig as well. My main application class looks like this:
#SpringBootApplication
#EnableSpringDataWebSupport
#EntityScan({"org.mdacc.ristore.fm.models"})
public class RistoreWebApplication extends SpringBootServletInitializer
{
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
public static void main( String[] args )
{
SpringApplication.run(RistoreWebApplication.class, args);
}
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RistoreWebApplication.class);
}
}
Since we are doing code consolidation, we need to turn off authentication temporarily. However, I tried the following methods and nothing seems to work. I am still getting 401 when I hit these rest api urls.
Comment out all the annotations in classes related to security including #Configuration, #EnableWebSecurity. In Spring boot Security Disable security, it was suggested at the bottom adding #EnableWebSecurity will DISABLE auth which I don't think make any sense. Tried it anyway, did not work.
Modify websecurityconfig by removing all the security stuff and only do
http
.authorizeRequests()
.anyRequest().permitAll();
Disable Basic Authentication while using Spring Security Java configuration. Does not help either.
Remove security auto config
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration.class})
like what they did in disabling spring security in spring boot app. However I think this feature only works with spring-boot-actuator which I don't have. So didn't try this.
What is the correct way disable spring security?
As #Maciej Walkowiak mentioned, you should do this for your main class:
#SpringBootApplication(exclude = org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class)
public class MainClass {
try this
1->Comment annotation #EnableWebSecurity in your security config
//#EnableWebSecurity
2->Add these lines in your security config
spring.security.enabled=false
management.security.enabled=false
security.basic.enabled=false
What worked for me is this. Creating WebFilter and PermitAll Request Exchange and disabling CSRF.
#Bean
public SecurityWebFilterChain chain(ServerHttpSecurity http, AuthenticationWebFilter webFilter) {
return http.authorizeExchange().anyExchange().permitAll().and()
.csrf().disable()
.build();
}
Just put this code in #SpringBootApplication class, Like this and will work like charm
#SpringBootApplication
public class ConverterApplication {
public static void main(String[] args) {
SpringApplication.run(ConverterApplication.class, args);
}
#Bean
public SecurityWebFilterChain chain(ServerHttpSecurity http, AuthenticationWebFilter webFilter) {
return http.authorizeExchange().anyExchange().permitAll().and()
.csrf().disable()
.build();
}

How to configure Spring ACL without XML file

I am trying to add ACL capabilities to my server. I have configured spring security using java file and would like to add ACL in the same manner. How should I do it? All the tutorials I found used XML file.
SecurityInit:
#Order(1)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfig
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
#Component
#ComponentScan(basePackages = {"test.package"})
public class SecurityConfig extends
WebSecurityConfigurerAdapter {
...
#Autowired
protected void registerAuthentication(UserDetailsService userDetailsService, AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
// http://stackoverflow.com/a/21100458/162345
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().disable()
.addFilterBefore(...)
.addFilterBefore(...)
// TODO: create a better way to differentiate login to signup
.exceptionHandling()
.authenticationEntryPoint(noRedirectForAnonymous)
.and()
.formLogin()
.successHandler(restAuthenticationSuccessHandler)
.failureHandler(restAuthenticationFailureHandler)
.and()
.logout()
.logoutSuccessHandler(noRedirectLogoutSuccessHandler)
.and()
.authorizeRequests()
.antMatchers("/api/keywords/**").permitAll()
.antMatchers("/api/**").authenticated();
}
}
You can configure spring acl with Java configuration class as follow
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ACLConfig extends GlobalMethodSecurityConfiguration {
#Autowired
DataSource dataSource;
EhCacheBasedAclCache aclCache() {
EhCacheFactoryBean factoryBean = new EhCacheFactoryBean();
EhCacheManagerFactoryBean cacheManager = new EhCacheManagerFactoryBean();
factoryBean.setName("aclCache");
factoryBean.setCacheManager(cacheManager.getObject());
return new EhCacheBasedAclCache(factoryBean.getObject());
}
LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ACL_ADMIN"),
new SimpleGrantedAuthority("ROLE_ACL_ADMIN"),
new SimpleGrantedAuthority("ROLE_ACL_ADMIN"));
}
#Bean
JdbcMutableAclService aclService() {
JdbcMutableAclService service = new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
service.setClassIdentityQuery("select currval(pg_get_serial_sequence('acl_class', 'id'))");
service.setSidIdentityQuery("select currval(pg_get_serial_sequence('acl_sid', 'id'))");
return service;
}
#Bean
AclMasterService masterService() {
return new AclMasterService();
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler(){
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
return expressionHandler;
}
}
The important aspect of the configuration are extend from
GlobalMethodSecurityConfiguration
override the method
createExpressionHandler
and enable the Pre and Post anotations with the follow anotation at the begining of the class
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled =
true)
Now you can use anotations like
#PreAuthorize('hasPermission(#object,read)')
see the Contact sample of Spring Security or the spring security reference guide for more uses of #Pre and #Post anotations.
This configuration class was tested on Spring 4 , Spring Security 4.0.1 and Spring Security ACL 3.1.2. If you want configure the authentication you can use a different Java class or override the configure method from this. If you already have a configured ehcache this configuration could not work correctly due to the ehcache is a singleton class and this configuration try to create a new one.
There is no way to configure spring acl without xml file. This is mentioned in spring docs itself.Refer to spring documentation.

Spring security AccessDecisionManager: roleVoter, Acl Voter

I'm trying to setup a Spring Security 3.2 project using Java Config and no XML at all.
I want to have an Access decision voter that supports both RoleHierarchyVoter and AclEntryVoters. This is the configuration I'm using:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AclEntryVoter aclUpdatePropertyVoter;
#Autowired
private AclEntryVoter aclDeletePropertyVoter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutSuccessUrl("/")
.and()
.authorizeRequests()
.accessDecisionManager(accessDecisionManager())
.antMatchers("/login", "/signup/email", "/logout", "/search", "/").permitAll()
.anyRequest().authenticated();
}
#Bean
public RoleHierarchyVoter roleVoter() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_USER > ROLE_ANONYMOUS");
RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy);
return roleHierarchyVoter;
}
#Bean
public AffirmativeBased accessDecisionManager() {
List<AccessDecisionVoter> decisionVoters = new ArrayList<>();
WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
decisionVoters.add(webExpressionVoter);
decisionVoters.add(roleVoter());
decisionVoters.add(aclDeletePropertyVoter);
decisionVoters.add(aclUpdatePropertyVoter);
AffirmativeBased affirmativeBased = new AffirmativeBased(decisionVoters);
return affirmativeBased;
}
}
However, when the app gets initialized I get the following exception:
I get the exception:
java.lang.IllegalArgumentException: AccessDecisionManager does not support secure object class: class org.springframework.security.web.FilterInvocation
When debugging the code I can see that when AbstractAccessDecisionManager is called and the following code is executed:
public boolean supports(Class<?> clazz) {
for (AccessDecisionVoter voter : this.decisionVoters) {
if (!voter.supports(clazz)) {
return false;
}
}
return true;
}
RoleHierarchyVoter support FilterInvocation, however AclEntryVoters fail to pass it. What I'm doing wrong in the configuration? How can I set the project so that it supports both types of voters? Thanks a lot in advance
As you've observed, the acl voters don't support filter invocations as they are intended for checking secured methods, not web requests.
You should configure a separate AccessDecisionManager for use with your method security and add the acl voters to that.

Resources