Custom WebSecurityConfigurerAdapter - spring

I have this problem implementing a custom login authentication using SpringBoot and SpringBoot-Security. I made a Bitbucket repository as reference for this thread (within CustomSecuringWeb branch). Before anything else, most of the comments here follows the Securing a Web Application tutorial.
The thing is, I was curious as how could the authentication data is now from the database instead of just memory data (which is very common in production line applications).
Throughout the process I made two attempts (though both attempts are located on the same branch - my bad for that).
Created a custom UserDetailsService implementation
Created a custom AbstractUserDetailsAuthentictionProvider implementation
I don't know where the problem lies, but upon checking the console log both returns that the persistence(even the repository) DI on each custom class where null.
The question is how could I make both attempts working. And (possibly) which one of the two attempts is better than the other.

First of all the two approaches are used for different purpose and not interchangeable.
Case 1:
UserDetailsService is used purely as DAO to locate user information by your authentication and based on that info authenticate user, no authentication should be done within UserDetailsService, just data access.
Specifications clearly mention that. This is what you are looking for.
Case2:
AuthentictionProvider on the other hand is used for providing custom method of authentication, for example if you want to custom authenticate on fields other than login and password you may do that by implementing AuthentictionProvider and supplying this object to your AuthenticationManagerBuilder. I do not think this is what you want to do in you project. You are just looking to implement your authentication based on users stored in database using login and password which is default way.
In above Case 1 where you implemented just UserDetailsService, instance of AuthentictionProvider was created for you in AuthenticationManager by the container and it was DaoAuthenticationProvider since you supplied UserDetailsService which is nothing else but DAO in your system that is used to retrive user for authentication.
Now to your implementation,
in your configuration instead of :
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(new AdminSecurityService());
auth.authenticationProvider(new AdminSecurityAuthenticationProvider());
}
do something like this
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
and your CustomUserDetailsService has to implement org.springframework.security.core.userdetails.UserDetailsService
#Service
public class CustomUserDetailsService implements UserDetailsService {
private final AdminRepository userRepository;
#Autowired
public CustomUserDetailsService(AdminRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Admin user = userRepository.findByLogin(username);
if (user == null) {
throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
}
return new UserRepositoryUserDetails(user);
}
private final static class UserRepositoryUserDetails extends Admin implements UserDetails {
private static final long serialVersionUID = 1L;
private UserRepositoryUserDetails(User user) {
super(user);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.createAuthorityList("ROLE_USER");
}
#Override
public String getUsername() {
return getLogin();//inherited from user
}
#Override
public boolean isAccountNonExpired() {
return true;//not for production just to show concept
}
#Override
public boolean isAccountNonLocked() {
return true;//not for production just to show concept
}
#Override
public boolean isCredentialsNonExpired() {
return true;//not for production just to show concept
}
#Override
public boolean isEnabled() {
return true;//not for production just to show concept
}
//getPassword() is already implemented in User.class
}
}
of course implementation is up to you but you have to be able to provide user password, and rest of the methods in that interface based on the retrieved user (Admin.class in your case). Hope it helps. I did not run this example so if I made some typos go ahead and ask if something does not work. I would also get rid of that 'AuthentictionProvider' from your project if you don't need it.
Here you got documentation:http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice
After comments:
You can set PasswordEncoder in your configure method without too much hassle just do:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
#Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
You can do that because you get access to AbstractDaoAuthenticationConfigurer returned from auth.userDetailsService(userDetailsService) and it allows you to configure DaoAuthenticationProvider, which is your provider of choice when you choose to use UserDetailsService.
You are right PasswordEncoder is set in AuthenticationProvider but you do not have to
implement AuthenticationProvider just use convineince object that is returned from auth.userDetailsService(userDetailsService) and set your encoder on that object which will pass it to AuthenticationPriovider in your case DaoAuthenticationProvider that was already created for you.
Just like roadrunner mentioned in the comment you very rarely need to implement your own AuthenticationProvider usually most of authentication configuration adjustments can be done with the use of AbstractDaoAuthenticationConfigurer which as mentioned above is returned from auth.userDetailsService(userDetailsService).
"And if I ever wanted to add a password encryption. And if I ever wanted to do other authentication (like checking if the user is locked, active, user is still logged-in, etc. [excluding password hashing]) will use the AuthenticationProvider."
No this is done for you as part of standard authentication mechanism
http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html
If you look at the interface UserDetails you will see that if any of the above methods returns false authentication will fail.
Implementing AuthenticationProvider is really needed in very nonstandard cases. All standard stuff is pretty much covered by the framework .

In a JDBC way http://www.mkyong.com/spring-security/spring-security-form-login-using-database/ basically, you have to specify the query to retrieve users.

Firstly I would encourage you to read about String Security Core Services.
A key one in this situation is AuthenticationManager that is responsible for deciding if the user is authenticated or not. This is what you configure with AuthenticationManagerBuilder. It's primary implementation in Spring is ProviderManager that allows to define multiple authentication mechanisms in a single applications. The most common use case is that there is one, but it is still handled by this class. Each of those multiple authentication mechanisms is represented by a different AuthenticationProvider. ProviderManager takes a list of AunthenticationProviders an iterates through them to see if any of them can authenticate the user.
What you are interested in is DaoAuthenticationProvider. As the name suggests, it allows to use a Data Access Object to authenticate the user. It uses a standard interface for such DAO - a UserDetailsService. There is a default implementation available in Spring Security, but usually this is the bit you will want to implement yourself. All the rest is provided.
Also, the configuration bit you need is totally independent from Spring Boot. This is how you'd do it in XML:
<sec:authentication-manager >
<sec:authentication-provider user-service-ref="myUserDetailsService" />
</sec:authentication-manager>
And in Java it will be:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService myUserDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
}
As per UserDetails implementation, usually the one provided by Spring Security is enough. But you can also implement your own if need be.
Usually you will also want a PasswordEncoder. A good one, like BCryptPasswordEncoder:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
}
Notice that it's a #Bean, so that you can #Autowire it in your UserRepository to encode user passwords as you save them in the database.

Related

Spring Boot not blocking request to the endpoint

Im having an issue with spring boot. I am trying to block one specific endpoint called /users/name/ but when i configure it on httpSecurity I can still call the endpoint. I need to block this specific endpoint below is my code.
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfigClass extends
WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().antMatchers("/users/name/").permitAll()
.anyRequest().authenticated().and().httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication().withUser("admin")
.password("{noop}password").roles("USER");
}
}
And this is the RestController. Note please that the intention of this app is to make it vulnerable to attacks like the OWASP TOP API so no worries about security issues please tough I accept suggestions.
#Api(value="Users Endpoint and maintenance only for prvileged users")
#RequestMapping("/users")
public class RestControllerMain {
private final UserRespository userRespository;
#Autowired
public RestControllerMain(UserRespository userRespository) {
this.userRespository = userRespository;
}
//Excessive Data Exposure OWASP TOP 10
#RequestMapping(value="/", method=RequestMethod.GET)
public Iterable<User> getAllUsers() {
return userRespository.findAll();
}
#RequestMapping(value="/", method=RequestMethod.POST)
public void UserInsert(#RequestBody User user) {
userRespository.save(user);
}
//null pointer exception and SQL injection OWASP TOP 10 API.
#RequestMapping(value="/name/{user}", method=RequestMethod.GET)
public String mainUser(#PathVariable ("user")String username) {
if(!username.matches("/[\\t\\r\\n]|(--[^\\r\\n]*)|(\\/\\*[\\w\\W]*?(?=\\*)\\*\\/)/gi\n" )) {
return "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘VALUE’’.";
}
return "SQL Injection not found";
}
//XSS Also in the OWASP TOP API.
#RequestMapping(value="/search", method=RequestMethod.GET)
public String getMeUSer(#RequestBody User user) {
return "Nice to meet you" + user.getName();
}
// OWASP TOP 10 API. Broken Object Level
#RequestMapping(value="/{id}")
public Optional<User> getUserById(#PathVariable Long id) {
return userRespository.findById(id);
}
}
Please help me figure this I ended up following a tutorial.
As I understood, you want to require authentication for "users/name/{user}" endpoint, but your configuration states
.antMatchers("/users/name/")
whereas it should be
.antMatchers("/users/name/**")
where "**" means any matching pattern. But you if want to grant access after checking the privileges, as you stated in the description of controller, you should configure Spring's authorization and add
#Secured("ROLE_VIEWER, ROLE_ADMIN")
before service or controller methods, which will block any user who doesn't have those roles.

How to define a custom UserDetailsService with WebSecurityConfigurerAdapter?

I'm a bit lost at how WebSecurityConfigurerAdapter should be correctly extended to properly use a custom UserDetailsService and expose it as a bean.
I mean, there are:
userDetailsService(): Javadoc says:
Allows modifying and accessing the UserDetailsService from
userDetailsServiceBean() without interacting with the
ApplicationContext. Developers should override this method when
changing the instance of userDetailsServiceBean().
userDetailsServiceBean(): Javadoc says:
Override this method to expose a UserDetailsService created from
configure(AuthenticationManagerBuilder) as a bean. [...] To change
the instance returned, developers should change
userDetailsService() instead
configure(AuthenticationManagerBuilder): Javadoc says:
[...] The authenticationManagerBean() method can be used to expose
the resulting AuthenticationManager as a Bean. The
userDetailsServiceBean() can be used to expose the last populated
UserDetailsService that is created with the
AuthenticationManagerBuilder as a Bean. The UserDetailsService
will also automatically be populated on
HttpSecurity#getSharedObject(Class) for use with other
SecurityContextConfigurer (i.e. RememberMeConfigurer)"
If I just read this, I understand that:
configure(AuthenticationManagerBuilder) configures an AuthenticationManager, which can be exposed by overriding authenticationManagerBean() to be marked with #Bean; to build this AuthenticationManager, configure(AuthenticationManagerBuilder) builds and wires a UserDetailsService
overriding userDetailsServiceBean() (to mark with #Bean) allows to expose the UserDetailsService built and wired by the previous method
if I want configure(AuthenticationManagerBuilder) to use my own implementation of UserDetailsService, I must override userDetailsService() to return it; it will be then exposed by overriding userDetailsServiceBean()
So I ended up with this:
#Override
protected void configure(final AuthenticationManagerBuilder auth)
throws Exception {
final MyUserDetailsService userDetailsService = userDetailsService();
auth.userDetailsService(userDetailsService);
// all the other configuration has been omitted
}
#Override
protected MyUserDetailsService userDetailsService() {
return new MyUserDetailsService();
}
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
However, this is what puzzles me and what I see:
the default implementation of configure(final AuthenticationManagerBuilder auth) substantially does nothing (just sets disableLocalConfigureAuthenticationBldr to true) and in particular it does not call userDetailsService(); it's my overriding that does it, so it's me that I'm injecting my custom UserDetailsService implementation through the use of userDetailsService(); in other words, if I don't override userDetailsService() and create the custom UserDetailsService instance in configure(final AuthenticationManagerBuilder auth) directly, I get the same result
probably related to the above: the default implementation of userDetailsService() is exactly identical to that of userDetailsServiceBean()... I would have expected the latter to delegate sooner or later to the former, but if the former default implementation is actually the same... I really get lost and I wonder why two distinct methods are provided
I would expect that, with the above, my custom MyUserDetailsService implementation is exposed in the application context, but if I try to inject a MyUserDetailsService instance somewhere else, Springs complains that there's no such instance in my application context; indeed, the bean returned by userDetailsServiceBean() is always some kind of delegating wrapper; if I inject a generic UserDetailsService instance and try to use it, I get an IllegalStateException saying that "UserDetailsService is required" (the delegation mechanism in org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.UserDetailsServiceDelegator.loadUserByUsername(String) fails to retrieve a proper default UserDetailsService...)
by debugging I see that userDetailsService() is invoked twice (hence creating two DISTINCT instances of MyUserDetailsService), once by the above implementation of configure(final AuthenticationManagerBuilder auth), and once by org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.createSharedObjects()...
So, the above is clearly incorrect (authentication works because the right UserDetailsService is injected into the AuthenticationManager, but it fails to expose the UserDetailsService in the application context) and I may probably overcome all these problems by simply marking a MyUserDetailsService bean with #Service or by writing yet another #Bean method in my WebSecurityConfigurerAdapter extension that returns an instance of my custom UserDetailsService, hence bypassing both userDetailsService() and userDetailsServiceBean()... But I'm not sure this is the best way to achieve the desired result (those two methods should have been put there for some reason...)
I really think WebSecurityConfigurerAdapter is overly complicated in how it handles this...
The way to configure custom UserDetailsService depends on the number ofUserDetailsServices and kind of UserDetailsService.
Also remember there are different ways to expose a bean in Spring: #Configuration with factory method (#Bean), #ComponentScan with #Component, XML etc.
One global UserDetailsService
If you want to use one global custom UserDetailsService you only have to expose it, see Spring Security Reference:
10.10.7. UserDetailsService
UserDetailsService is used by DaoAuthenticationProvider for retrieving a username, password, and other attributes for authenticating with a username and password. Spring Security provides in-memory and JDBC implementations of UserDetailsService.
You can define custom authentication by exposing a custom UserDetailsService as a bean. For example, the following will customize authentication assuming that CustomUserDetailsService implements UserDetailsService:
This is only used if the AuthenticationManagerBuilder has not been populated and no AuthenticationProviderBean is defined.
Example 66. Custom UserDetailsService Bean
#Bean
CustomUserDetailsService customUserDetailsService() {
return new CustomUserDetailsService();
}
The default implementations of userDetailsService() and userDetailsServiceBean() return the global UserDetailsService. There is no need to override these methods.
Different UserDetailsServices
If you want to use different UserDetailsServices for different WebSecurityConfigurerAdapters you could override WebSecurityConfigurerAdapter#configure:
Used by the default implementation of authenticationManager() to attempt to obtain an AuthenticationManager. If overridden, the AuthenticationManagerBuilder should be used to specify the AuthenticationManager.
and add it with AuthenticationManagerBuilder#userDetailsService:
Add authentication based upon the custom UserDetailsService that is passed in. It then returns a DaoAuthenticationConfigurer to allow customization of the authentication.
The default implementations of userDetailsService() and userDetailsServiceBean() return the UserDetailsService of the AuthenticationManagerBuilder.
If you want to inject the UserDetailsService to another component, you could override userDetailsServiceBean(). If you expose more than one UserDetailsService you have to use different bean names.
Built-in UserDetailsService
There are some built-in UserDetailsServices created by AuthenticationManagerBuilder, which are not exposed.
If you need such an UserDetailsService in another component, you have to override
userDetailsServiceBean(), see WebSecurityConfigurerAdapter#configure:
For example, the following configuration could be used to register in memory authentication that exposes an in memory UserDetailsService:
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
// enable in memory based authentication with a user named
// "user" and "admin"
.inMemoryAuthentication().withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
// Expose the UserDetailsService as a Bean
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
If you expose more than one UserDetailsService you have to use different bean names.

Is #Order really needed in Spring Boot 2.0.4 OAuth server?

I have this little OAuth server class and I am using Spring Boot 2.0.4 and the spring-security-oauth2-autoconfigure 2.0.0.RELEASE dependency :
#RestController
#SpringBootApplication
#EnableAuthorizationServer
#Order(200) // really needed ?
public class MyOAuthServerApplication extends WebSecurityConfigurerAdapter {
#RequestMapping({ "/me" })
public Map<String, String> user(Principal principal) {
Map<String, String> map = new LinkedHashMap<>();
map.put("name", principal.getName());
return map;
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/me").authorizeRequests().anyRequest().authenticated();
// #formatter:on
}
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails mary =
User.withUsername("mary")
.password("{bcrypt}$2a$10$B3NUb0x.MYnSfx7WJItrvO/ymEQwLCKQNehmCuA8keL1uTyHizI0i")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(mary);
}
public static void main(String[] args) {
SpringApplication.run(MyOAuthServerApplication.class, args);
}
}
This seems to work well with and without the #Order(200) annotation.
So is this annotation really needed ?
The Order annotation is used to define the injection precedence.
Read more her: https://www.baeldung.com/spring-order
In your case it's because of the EnableResourceServer annotation. And you must keep the annotation.
From the doc:
The #EnableResourceServer annotation creates a security filter with
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER-1) by default, so by
moving the main application security to
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) we ensure that the
rule for "/me" takes precedence.
Please find the tutorial here: https://spring.io/guides/tutorials/spring-boot-oauth2/
You need it if you have another WebSecurityConfigurerAdapter configuration.
For example if you allow users to login via login form with a different UserDetailsService and so on. Then this should be tried before your oauth authentification and thus needs a lower order, for example #Order(199).
Another example would be different configuration for your API access.
If you don't have any other configuration, then you don't need to set the order.
Setting the order to 200 also seems to be an arbitrary value, that should simply be higher then the others and thus executed last.

userRepository insecure as userDetailsService needs to look up user

I have implemented a custom UserDetailsService that looks up a user and allows them to get a oauth 2 token using password grant. The service indicates to use a JPA userRepository to look up the user.
This all works, except that now I have a /users endpoint publicly available pulling in all users and passwords to any authenticated user. Ideally I would like to not have this endpoint available at all, but if I put a preAuthorize on it with admin role, then all users are denied while trying to obtain a login token too, so this doesn't work either. How do people get around this issue? I can add a matcher to resource server to only allow admin users, this seems to work, but I don't want the endpoint available at all, it's quite scary to have it there just so UserDetailsService can use it to get access tokens?
Any input on what you guys do would be greatly appreciated.
//Example code:
// Bad public facing endpoint returning all users and passwords
public interface UserRepository extends JpaRepository<User, Long> {
User findOneByUsername(String username);
}
// Custom user details service used by oauth 2 to get access tokens
// uses userRepo above
#Service("userDetailsService")
public class UserService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findOneByUsername(username);
}
}
// class using user details service
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
configurer.userDetailsService(userDetailsService);
}
}
I presume that you are using Spring Data?
In that case, you need to tell Spring not to export the endpoint:
#RepositoryRestResource(exported = false)
https://docs.spring.io/spring-data/rest/docs/current/api/org/springframework/data/rest/core/annotation/RepositoryRestResource.html

Design, Authentication and Authorization strategy needed for a Spring MVC application using Spring Security

I am learning Spring-MVC and Spring-security. I decided to create a project in which I can practice the concepts. What I need help in is coming up with a strategy for authorizing and Authenticating my users. Any examples you can reference or ideas you can provide me would be very helpful for my design.
Application Synopsis:
The application will allow users to create artwork on like an HTML5
canvas and share it with the world. People can comment on the artwork
if they have the permalink to it and are authorized to see it. The
creator of the artwork allows this art to either be public or password
secured.
Here is the usage workflow:
User logs in
-> is directed to their profile page containing list of
several artworks -> User can choose to edit or delete an existing art. ->
User can also create a new art. Each artwork should have a permalink that the
user can share with the world by making it public or password protected/public.
I am not sure where to begin designing this thing as I am a rookie. Can someone provide advice on how to handle this use-case in terms of designing/architecting this application?
Looking at the requirements I can see not much of Spring Security design, this can be easily managed with more or less basic Spring Security configuration.
For authentication part I would go with implementing UserDetails and UserDetailsService interfaces, i.e. creating custom authentication provider. UserDetails covers domain model logic representing Spring Security-aware entity on this layer. This is usually combined with application User entity, like this:
#Entity
#Table(name="APP_USER")
public class User implements Serializable, UserDetails {
#Id
#Column(name="ID")
private Long id;
#Column(name="IS_ACTIVE", nullable=false)
private Boolean isActive;
#Column(name="USERNAME", nullable=false, unique=true)
private String username;
#Column(name="PASSWORD", nullable=false)
private String password;
…
#Override
public String getPassword() {
return password;
}
#Override
public boolean isEnabled() {
return isActive;
}
#Override
public boolean isCredentialsNonExpired() {
return isActive;
}
#Override
public boolean isAccountNonLocked() {
return isActive;
}
#Override
public boolean isAccountNonExpired() {
return isActive;
}
#Override
public Set<GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return authorities;
}
}
Notice a number of overridden methods, this is a consequence of implementing UserDetails and required for authentication to work properly.
UserDetailsService resides on a service layer and represents Spring Security-compatible implementation of authentication provider which works with UserDetails objects:
#Service
public class UserServiceImpl implements UserService, UserDetailsService {
…
#Override
#Transactional(readOnly=true)
public UserDetails loadUserByUsername(String username) {
return userDao.getUserByUsername(username);
}
}
Here too you are free to combine it with your services, for instance working with application user entity. The example implies using DAO to fetch UserDetails objects which depends on your persistence framework.
Regarding protecting the images with passwords I would not go with Spring Security for this since for me it sounds more like a functional requirement rather than security one.

Resources