I have setup a auth server and resource server as mentioned in the below article
http://www.hascode.com/2016/03/setting-up-an-oauth2-authorization-server-and-resource-provider-with-spring-boot/
I downloaded the code and it is working fine. Now the issue is that in the resource provider project there is only one RestController annotated class as shown below
package com.hascode.tutorial;
import java.util.UUID;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Scope;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RestController
#EnableResourceServer
public class SampleResourceApplication {
public static void main(String[] args) {
SpringApplication.run(SampleResourceApplication.class, args);
}
#RequestMapping("/")
public String securedCall() {
return "success (id: " + UUID.randomUUID().toString().toUpperCase() + ")";
}
}
Now when I create a different class annotated with #RestController as shown below
#RestController
#RequestMapping("/public")
public class PersonController {
#Autowired
private PersonRepository personRepo;
#RequestMapping(value = "/person", method = RequestMethod.GET)
public ResponseEntity<Collection<Person>> getPeople() {
return new ResponseEntity<>(personRepo.findAll(), HttpStatus.OK);
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<Person> getPerson(#PathVariable long id) {
Person person = personRepo.findOne(id);
if (person != null) {
return new ResponseEntity<>(personRepo.findOne(id), HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
}
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> addPerson(#RequestBody Person person) {
return new ResponseEntity<>(personRepo.save(person), HttpStatus.CREATED);
}
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deletePerson(#PathVariable long id, Principal principal) {
Person currentPerson = personRepo.findByUsername(principal.getName());
if (currentPerson.getId() == id) {
personRepo.delete(id);
return new ResponseEntity<Void>(HttpStatus.OK);
} else {
return new ResponseEntity<Void>(HttpStatus.UNAUTHORIZED);
}
}
#RequestMapping(value = "/{id}/parties", method = RequestMethod.GET)
public ResponseEntity<Collection<Party>> getPersonParties(#PathVariable long id) {
Person person = personRepo.findOne(id);
if (person != null) {
return new ResponseEntity<>(person.getParties(), HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
}
}
but when I tried to access the service (http://localhost:9001/resources/public/person) I am getting 404
{
"timestamp": 1508752923085,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/resources/public/person"
}
when I access http://localhost:9001/resources/ I am getting the correct result like
success (id: 27DCEF5E-AF11-4355-88C5-150F804563D0)
Should I register the Contoller anywherer or am I missing any configuration
https://bitbucket.org/hascode/spring-oauth2-example
UPDATE 1
ResourceServerConfiguration.java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().and()
.authorizeRequests()
.antMatchers("/resources/public/**").permitAll()
.antMatchers("/resources/private/**").authenticated();
}
}
OAuth2SecurityConfiguration.java
import org.springframework.context.annotation.Configuration;
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;
#Configuration
#EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().and()
.authorizeRequests()
.antMatchers("/resources/public/**").permitAll()
.antMatchers("/resources/private/**").authenticated();
}
}
UPDATE 2
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/public/**").permitAll() //Allow register url
.anyRequest().authenticated().and()
.antMatcher("/resources/**").authorizeRequests() //Authenticate all urls with this body /api/home, /api/gallery
.antMatchers("/resources/**").hasRole("ADMIN")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); //This is optional if you want to handle exception
}
Make your new controller PersonController discoverable by Spring Boot either by using #ComponentScan on a configuration class or by moving PersonController to a package in or under your main class annotated with #SpringBootApplication.
Second fix your OAuth2SecurityConfiguration class like so
#Configuration
#EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll(); //This will permit the (oauth/token) url for getting access token from the oauthserver.
}
}
Now fix your resource server like so
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/v1/register", "/api/v1/publicOne", "/api/v1/publicTwo").permitAll() //Allow urls
.anyRequest().authenticated().and()
.antMatcher("/api/**").authorizeRequests() //Authenticate all urls with this body /api/home, /api/gallery
.antMatchers("/api/**").hasRole("ADMIN")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); //This is optional if you want to handle exception
}
}
Find the complete source code here. Hope this helps.
Note: You can customize your urls based on the above answer.
Why your request url is http://localhost:9001/resources/public/person
I think it should be like http://localhost:9001/public/person
Related
I have been struggling on this issue for 2 days. I have a simple Springboot application with spring security. When I tested my controller using Swagger and Postman, there is no issue. However, when I call the same endpoint from my front-end app, it throws the error below
2022-10-07T21:43:51.991+0800 DEBUG http-nio-8080-exec-1 (FilterChainProxy.java:323) - Secured OPTIONS /category/all 2022-10-07T21:43:51.993+0800 DEBUG http-nio-8080-exec-1 (LogFormatUtils.java:119) - OPTIONS "/category/all", parameters={} 2022-10-07T21:43:51.995+0800 DEBUG http-nio-8080-exec-1 (PropertySourcedRequestMappingHandlerMapping.java:108) - looking up handler for path: /category/all 2022-10-07T21:43:51.998+0800 DEBUG http-nio-8080-exec-1 (AbstractHandlerMapping.java:522) - Mapped to com.edar.sales.be.controller.CategoryController#getAllCategories() 2022-10-07T21:43:52.002+0800 DEBUG http-nio-8080-exec-1 (OpenEntityManagerInViewInterceptor.java:86) - Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-10-07T21:43:52.015+0800 DEBUG http-nio-8080-exec-1 (HttpSessionSecurityContextRepository.java:346) - Did not store anonymous SecurityContext 2022-10-07T21:43:52.018+0800 DEBUG http-nio-8080-exec-1 (OpenEntityManagerInViewInterceptor.java:111) - Closing JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-10-07T21:43:52.019+0800 DEBUG http-nio-8080-exec-1 (FrameworkServlet.java:1131) - Completed 403 FORBIDDEN
This is my Controller Class
package com.edar.sales.be.controller;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.edar.sales.be.dto.CategoryDTO;
import com.edar.sales.be.entity.Category;
import com.edar.sales.be.service.CategoryService;
import com.google.gson.Gson;
#RestController(value = "category/")
public class CategoryController {
private static final Logger LOG = LoggerFactory.getLogger(CategoryController.class);
private static final Gson GSON = new Gson();
#Autowired
CategoryService categoryService;
#GetMapping(value = "category/all")
public List<CategoryDTO> getAllCategories() throws IllegalAccessException, InvocationTargetException {
List<CategoryDTO> retval = new ArrayList<>();
List<Category> categories = categoryService.getAllCategories();
for (Category category : categories) {
CategoryDTO categoryDTO = new CategoryDTO();
BeanUtils.copyProperties(categoryDTO, category);
retval.add(categoryDTO);
}
return retval;
}
#GetMapping(value = "category/{id}")
public CategoryDTO getCategoryById(#PathVariable("id") long id) throws IllegalAccessException, InvocationTargetException {
CategoryDTO categoryDTO = new CategoryDTO();
BeanUtils.copyProperties(categoryDTO, categoryService.getCategoryById(id));
return categoryDTO;
}
#PostMapping(value = "category/delete/{id}")
public void deleteCategoryById(#PathVariable("id") Long id) {
categoryService.deleteCategoryById(id);
}
#PostMapping(value = "category/add")
public void addCategory(#RequestBody Category category) {
LOG.debug("Adding category : {}", GSON.toJson(category));
categoryService.addCategory(category);
}
#PatchMapping(value = "category/update")
public void updateCategory(#RequestBody Category category) {
LOG.debug("Updating category : {}", GSON.toJson(category));
categoryService.addCategory(category);
}
}
And this is my SecurityConfig
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("**").permitAll();
}
}
Try using this and also use SecurityFilterChain for spring security because WebSecurityConfigurerAdapter is deprecated.
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests().antMatchers("/**").permitAll()
.and
.httpBasic();
}
}
I am trying to update Spring Boot application from 2.4 to 2.6.4 but I am getting following error:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| webSecurityConfig
↑ ↓
| org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration.
└─────┘
Following is WebSecurityConfig code:
import javax.sql.DataSource;
import com.jay.liqui.jwt.JWTAuthorizationFilter;
import com.jay.liqui.jwt.JwtTokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.core.annotation.Order;
#Configuration
//#Order(1)
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private JwtTokenProvider jwtTokenProvider;
#Bean
public static PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//Cross-origin-resource-sharing: localhost:8080, localhost:4200(allow for it.)
http.cors().and()
.authorizeRequests()
//These are public paths
.antMatchers("/resources/**", "/error", "/api/user/**").permitAll()
//These can be reachable for just have admin role.
.antMatchers("/api/admin/**").hasRole("ADMIN")
//All remaining paths should need authentication.
.anyRequest().fullyAuthenticated()
.and()
//logout will log the user out by invalidated session.
.logout().permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher("/api/user/logout", "POST"))
.and()
//login form and path
.formLogin().loginPage("/api/user/login").and()
//enable basic authentication
.httpBasic().and()
//We will handle it later.
//Cross side request forgery
.csrf().disable();
//jwt filter
http.addFilter(new JWTAuthorizationFilter(authenticationManager(),jwtTokenProvider));
}
#Autowired
public void configAuthentication(AuthenticationManagerBuilder authBuilder) throws Exception {
authBuilder.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(new BCryptPasswordEncoder())
.usersByUsernameQuery("select username, password, enabled from usr01 where username=?")
.authoritiesByUsernameQuery("select username, role from usr01 where username=?")
;
}
//Cross origin resource sharing.
#Bean
public WebMvcConfigurer corsConfigurer(){
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}
};
}
}
The cause of this error is
Spring Boot 2.4 disable spring.main.allow-bean-definition-overriding by default and Spring Boot 2.6.4 enable
There are 2 solutions to fix it
Solution 1: You set allow-bean-definition-overriding is true in application.properties
spring.main.allow-bean-definition-overriding=true
Solution 2: You should move Bean WebMvcConfigurer to another class
Example:
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Autowired
LogInterceptor logInterceptor;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/swagger-ui.html");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor);
}
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}
#Bean
public InternalResourceViewResolver defaultViewResolver() {
return new InternalResourceViewResolver();
}
}
#Component
public class LogInterceptor implements HandlerInterceptor {
#Autowired
LoggingService loggingService;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (DispatcherType.REQUEST.name().equals(request.getDispatcherType().name()) && request.getMethod().equals(HttpMethod.GET.name())) {
loggingService.logRequest(request, null);
}
return true;
}
#Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
#Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
I am new to spring boot. I am trying to implement a simple spring boot security with userdetailsservice in Spring Tool Suite(STS).
Below is the controller I used:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HomeController {
#GetMapping("/")
public String home() {
return("<h1>Welcome</h1>");
}
#GetMapping("/user")
public String user() {
return("<h1>Welcome user</h1>");
}
}
And the Web security configuration code:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#EnableWebSecurity
public class AppSecureConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user").hasRole("USER")
.antMatchers("/").permitAll()
.and().formLogin()
.and().logout().permitAll();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
I gave all the required dependencies in pom.xml.
So, I have added below line in application.propperties file, and now system is not generating security password.
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
And I have included user details Service for credentials.
Below is user detail service class
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
#Service
public class MyuserDetails implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return new userPrincipal(s);
}
}
and userPrincipal class
import java.util.Arrays;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class userPrincipal implements UserDetails {
private static final long serialVersionUID = 1L;
private String userName;
public userPrincipal(String userName) {
this.userName = userName;
}
public userPrincipal() {
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
#Override
public String getPassword() {
// TODO Auto-generated method stub
return "pass";
}
#Override
public String getUsername() {
// TODO Auto-generated method stub
return userName;
}
#Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
now, when I ran the application using http://localhost:8081/ url, it is giving "No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken".
I am using Spring tool suite(STS) to run this project. Can some one point out what am I doing wrong here?
Do not exclude the entire SecurityAutoConfiguration, instead if you want you should just exclude the org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.
Alternatively, you can expose a UserDetailsService bean that will do the same for you, and you can get rid of the configureGlobal method, like so:
#Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
Add this to your application.properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
And your class will look like this:
Add #Configuration to the class (as suggested by M. Deinum)
Specify the role for the user, otherwise you will get java.lang.IllegalArgumentException: Cannot pass a null GrantedAuthority collection
#Configuration
#EnableWebSecurity
public class AppSecureConfig extends WebSecurityConfigurerAdapter {
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("{noop}"+"pass").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user").hasRole("USER")
.antMatchers("/").permitAll()
.and().formLogin()
.and().logout().permitAll();
}
}
I am trying to secure a REST endpoint via the #Secured annotation of Spring Security. My main application (Spring Boot App) with the security config and the rest controller are in different packages and project.
Main app package: com.myapp.api.web
Rest controller packge: com.myapp.api.rest
Mainapp:
#SpringBootApplication
#ComponentScan(basePackages = "com.myapp.api")
#EntityScan("com.myapp.api")
#RestController
public class ApiApplication extends SpringBootServletInitializer
{
public static void main(String[] args)
{
SpringApplication.run(ApiApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(ApiApplication.class);
}
}
Security Config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true,
securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
private static final String USERS_CONFIG_FILE_NAME = "users.yml";
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.httpBasic()
.and()
.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
InMemoryUserDetailsManager inMemoryUserDetailsManager, PasswordEncoder passwordEncoder) throws Exception
{
auth.userDetailsService(inMemoryUserDetailsManager).passwordEncoder(passwordEncoder);
}
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() throws IOException
{
return new InMemoryUserDetailsManager(
PropertiesLoaderUtils.loadAllProperties(USERS_CONFIG_FILE_NAME, getClass().getClassLoader()));
}
}
Rest controller:
#RestController
public class RestController
{
private final RestService service;
#PostMapping("/rest/v1")
#Secured({"ROLE_ADMIN"})
public List<String> getStates(#RequestBody List<String> Ids)
{
...
}
My rest endpoint is working as long as I am not setting securedEnabled = true. After setting it true I am getting a 404 Not Found as respond message. I've already debugged it and found out that the Spring Security somewhen stops in the filter chain and that the request never reaches the controller.
As far as I tested it, as long as the rest controller is in a different project this error will occure. After moving it to the same project it is working as it should.
Is there something missing in my Securityconfig or what could the problem be?
I am able to get values by your code , I have only changed Password Encoder to default and changed inMemoryAuthentication .
I did it as I don't have your file "users.yml" If you can share a sample , we will look in it , But below is my code. I kept all logic in 2 files just to verify.
Configuration Class
package com.myapp.api.web.Api;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true,
securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
private static final String USERS_CONFIG_FILE_NAME = "users.yml";
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.httpBasic()
.and()
.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder() {
#Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equals(encodedPassword);
}
};
}
#Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.inMemoryAuthentication()
.withUser("user").password("user").roles("USER")
.and().withUser("admin").password("admin").roles("ADMIN");
}
/*
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() throws IOException
{
return new InMemoryUserDetailsManager(
PropertiesLoaderUtils.loadAllProperties(USERS_CONFIG_FILE_NAME, getClass().getClassLoader()));
}*/
}
Main Class
package com.myapp.api.web.Api;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#ComponentScan(basePackages = "com.myapp.api")
#RestController
#SpringBootApplication
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
#PostMapping("/rest/v1")
#Secured({"ROLE_ADMIN"})
public List<String> getStates(#RequestBody List<String> Ids)
{
return Ids;
// ...
}
}
I have a problem concerning Spring Boot role based authentication. Basically, I would like to have users and admins and I want to prevent users from accessing admin resources. So I created a SecurityConfig class:
package test;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("password1").roles("USER, ADMIN")
.and()
.withUser("user2").password("password2").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/service/test").access("hasRole('USER') or hasRole('ADMIN')")
.antMatchers("/service/admin").access("hasRole('ADMIN')");
}
}
This is my little REST service:
package test;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/service")
public class RestService {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String echo() {
return "This is a test";
}
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String admin() {
return "admin page";
}
}
And my Application class:
package test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Unfortunately, I always get a 403 "forbidden/access denied" error message when executing "curl user1:password1#localhost:8080/service/admin"... Did I miss anything in the configure method?
Thank you very much in advance!
Can you please check this.
withUser("user1").password("password1").roles("USER", "ADMIN")
write "USER" and "ADMIN" in separate qoutes.
I changed it in the following way, now it seems to be working:
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("password1").roles("USER", "ADMIN")
.and()
.withUser("user2").password("password2").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().permitAll()
.and()
.authorizeRequests()
.antMatchers("/service/test").hasAnyRole("USER", "ADMIN")
.antMatchers("/service/admin").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
Thank you very much for your answers!
following setup works fine for my spring boot app:
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()//allow CORS option calls
.antMatchers("/home", "/").hasAnyAuthority(Role.ROLE_ADMIN, Role.ROLE_USER)
.antMatchers("/admin").hasAuthority(Role.ROLE_ADMIN)enter code here