Bean initialisation, PreAuthorize and GlobalAuthenticationConfigurerAdapter - spring

follow configuration is not work, since i have used the #PreAuthorize annotation.
I would like to inject a service in my own AuthenticationProvider. If my service not use the #PreAuthorize annotation, it will work. If i use this annotation, the "my service " bean will be null at the "MyGlobalAuthenticationConfigurerAdapter", because when the my service bean is created the authentification provider is created too (to early). So what can i do?
MyService:
interface MyService{
#PreAuthorize()
void foo(){
}
Config 1:
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class MyConfiguration {
#Bean
public MyService myService() {
return new MyServiceimpl();
}
Config2:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
#Autowired
private MyService myService;
#Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
final MyAuthenticationProvider myAuthenticationProvider = myAuthenticationProvider ();
auth.authenticationProvider(myAuthenticationProvider );
}
#Bean
public MyAuthenticationProvider myAuthenticationProvider () {
return new MyAuthenticationProvider (myService);
}

Related

Security configuration with spring boot

I'm a beginner, I want to code the password when adding users but there is an error (#Bean).
Error:
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Description:
Field passwordEncoder in com.example.demo.service.UsersService required a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' in your configuration.
My code:
#Configuration
#EnableConfigurationProperties
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UsersService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.csrf().disable() //TODO implement csrf
.cors().and().authorizeRequests().antMatchers(HttpMethod.OPTIONS,"/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/add-users").permitAll()
.and().authorizeRequests().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
auth.userDetailsService(userService)
.passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
// TODO Auto-generated method stub
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
public class UsersService implements UserDetailsService {
#Autowired
UsersRepository repo;
#Autowired
private PasswordEncoder passwordEncoder;
public Users save(Users u) {
String encodpass=passwordEncoder.encode(u.getPassword());
String confpass=passwordEncoder.encode(u.getConfirmepass());
u.setConfirmpass(confpass);
u.setPassword(encodpass);
u.setLock(false);
u.setEnable(true);
return repo.save(u);
}
}
#RestController
public class UsersController {
#Autowired
private UsersService service;
#PostMapping("/add-users")
public Users add(#RequestBody Users u) {
return service.save(u);}
The problem is that in your SecurityConfiguration you are injecting UsersService, and the UserService bean depends on a bean of type PasswordEncoder that has not been created yet.
I'll simplify your configuration by using a more ellegant way of configuring Spring Security:
#Configuration
//your other annotations
public class SecurityConfiguration {
#Bean
public SecurityFilterChain app(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and().authorizeRequests().antMatchers(HttpMethod.OPTIONS,"/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/add-users").permitAll()
.and().authorizeRequests().anyRequest().authenticated();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
And that's it, you don't really need the AuthenticationManager bean unless you are actually using it. In case that you need it, you can create it like this:
#Bean
public AuthenticationManager authenticationManager(UsersService usersService) {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(usersService);
ProviderManager manager = new ProviderManager(daoAuthenticationProvider);
return manager;
}
I apologize for any compilation error beforehand because I wrote this from a phone.
add #Service annotation to UserService class. also add #EnableWebSecurity to config class.

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

Method security not working if I implement UserDetailsService in #Service

I've implemented Spring Security on my project. But method security annotations ignored if I implement UserDetailsService on #Service.
What's wrong with this code?
#Transactional
public interface UserService extends UserDetailsService {
#PreAuthorize("hasRole('ROLE_SUPER')") /* it's ignored. */
void update(UserEditForm form);
#Override
User loadUserByUsername(String username) throws UsernameNotFoundException;
}
#Service
public class SimpleUserService implements UserService {
// ommitted
}
#Transactional
public interface SomeService{
#PreAuthorize("hasRole('ROLE_SUPER')") /* it's working fine */
void doSomething();
}
#Service
public class SimpleSomeService implements SomeService {
// ommitted
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
UserService userService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
}
// ommitted
}
ps: Sorry I don't have well enough english knowledge.
You need to make changes in SimpleUserService like this
#Service("simpleUserService")
public class SimpleUserService implements UserService {
// ommitted
}
and in SecurityConfig, Autowire UserService with #Qualifier("simpleUserService")
#Autowired
#Qualifier("simpleUserService")
UserService userService;
Do not annotate the interfaces with Spring annotations(#Component, #Service, #Transactional, #Repository), Add the annotations on the implementation classes.
Remove #Transactional on UserService interface, Create new class UserServiceImpl and add annotation #Transactional.
and also move the #PreAuthorize("hasRole('ROLE_SUPER')") annotation on to the implementation method.

spring #PreAuthorize not working with #EnableGlobalMethodSecurity(prePostEnabled = true)

Here is my code:
#Configuration
#ComponentScan(basePackages = "com.webapp")
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests().antMatchers("/resources/**").permitAll().
antMatchers("/admin/**").hasRole("ADMIN").
anyRequest().authenticated().
and().
formLogin().loginPage("/login").permitAll().
and().
logout().permitAll();
}
#Autowired
public void configureGlobal(UserDetailsService userDetailsService, AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService);
}
}
when a request /admin/* comes in, it will verify if the user has admin role by calling "antMatchers("/admin/**").hasRole("ADMIN")." , but in my controller, it does not check if the user has other permissions with #PreAuthorize .
#Controller
#SessionAttributes({ "user" })
#RequestMapping(value = "/admin/user")
public class UserController {
static Logger logger = LoggerFactory.getLogger(UserController.class);
#Autowired
private RoleDAO roleDao;
#Autowired
private MessageSource messageSource;
#Autowired
private UserDAO userDao;
#RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET)
#PreAuthorize("hasRole('USER_VIEW')")
public ModelAndView listUsers() {
List<User> users = userDao.list();
ModelAndView model = new ModelAndView("/admin/user/user-list");
model.addObject("users", users);
if (model.getModel().get("user") == null) {
model.getModel().put("user", new User());
}
this.loadRoles(model);
return model;
}
}
Normally, Spring Security becomes available in the root application context and Spring MVC beans are initialized in a child context.
Hence org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor can't detect your controller beans because they live in a child context that is unknown to the root context.
#EnableGlobalMethodSecurity or <global-method-security> has to be placed inside the same configuration class or xml file where your Spring MVC configration lives in order to enable #PreAuthorize and #PostAuthorize.
try to add #EnableGlobalMethodSecurity(prePostEnabled = true) above your Security configuration class. It is works to me!

Wiring ClientRegistrationService with jdbc datasource

I could successfully set the jdbc datasource to Spring OAuth2 using the following configuration. However I am struggling to wire ClientRegistrationService while it was easy to wire ClientDetailsService.
#Configuration
#EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
.....
}
Here is what I tried
Below code fails to find the ClientDetailsService is not instanceof or of assignableFrom JdbcClientDetailsService or ClientRegistrationService
#Controller
public class ClientPortalApplication {
private ClientRegistrationService clientService;
#Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
if (clientDetailsService instanceof JdbcClientDetailsService)) {
clientService = (ClientRegistrationService) clientDetailsService;
}
}
......
}
Below code wiring fails on finding a bean of type ClientRegistrationService
:
#Controller
public class ClientPortalApplication {
#Autowired
private ClientRegistrationService clientService;
......
}
The ClientDetailsService created in yout AuthorizationServerConfigurerAdapter is not a bean therefore can't be injected. A solution is to create a bean JdbcClientDetailsService inject it in the AuthorizationServerConfigurerAdapter and you will be able to inject it anywhere else:
#Configuration
public class MyConfiguration {
#Autowired
private DataSource dataSource;
#Bean
public JdbcClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
#Configuration
#EnableAuthorizationServer
protected class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private JdbcClientDetailsService jdbcClientDetailsService;
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(jdbcClientDetailsService);
}
}
}

Resources