I develops a some RestController and I'm using something like
#PreAuthorize(“hasRole(‘ADMIN')”)
for the authorization.
I'm using oauth (google API) for the authentification. And I would like used own DB for authorization (managed and other user data).
What are good practices ? How can I resolved this issue (may use filter) ?
If you want to use your own database for authentication then you can make use of UserDetailsService interface which is used in order to lookup the username, password and GrantedAuthorities for any given user.
This interface provide only one method which implementing class need to implement-
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
Create a class which implements this interface and override a above method to get the user details from your DB.(Annotate this class with #Service annotation) Here you can call your DB to get the users details by provided userName and convert it to UserDetails.
Create a custom MyUserdetails class which implements UserDetails interface. And implement all required methods.
Now create a class say SecurityConfiguration which extends WebSecurityConfigurerAdapter annotate this class with #EnableWebSecurity.(The #EnableWebSecurity is a marker annotation. It allows Spring to find (it's a #Configuration and, therefore, #Component) and automatically apply the class to the global WebSecurity.) In this class autowire UserDetailsService bean and override a following method to get users details from your DB.
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
Add following dependency in you pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Also annotate you main class with following annotation to let spring know that you are using JPA
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
Hope this helps.
Related
I just read answer from the another question What is the use of #EnableWebSecurity in Spring?, but i couldn't understand why we need to add #EnableWebSecurity annotation at all.
Even I remove the #EnableWebSecurity from the configuration, my application still works.
Let's assume that we are going to implement either JWT based (rest api) or simply login based mvc application. For the following configuration what i am missing?
#Component
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public UserDetailsService userDetailsService() {
return new MyCustomUserDetailsService();
}
#Bean
public PasswsordEncoder passwsordEncoder() {
return new BrcyptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// for the jwt authentication add jwt filter etc ..
// for the login based, override default login page, error page etc..
}
}
If you are not using spring-boot but just a pure spring project , you definitely need to add #EnableWebSecurity in order to enable spring-security.
But if you are using spring-boot 2.0 +, you do not need to add it by yourself because the spring-boot auto configuration will automatically do it for you if you forget to do so. Under the cover , it is done by the WebSecurityEnablerConfiguration which its javadoc also states this behaviour as follows:
If there is a bean of type WebSecurityConfigurerAdapter, this adds the
#EnableWebSecurity annotation. This will
make sure that the annotation is present with default security
auto-configuration and also if the user adds custom security and
forgets to add the annotation.
We are in the process of migrating a legacy application to Spring Boot. In order to continue with testing until we have assigned roles to users, I would like to override the following:
class: SecurityContextHolderAwareRequestWrapper
method: public boolean isUserInRole(String role)
I have created a new class which extends SecurityContextHolderAwareRequestWrapper and overrides isUserInRole(), as follows:
#Component
public class MySecurityContextHolderAwareRequestWrapper extends org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper {
public MySecurityContextHolderAwareRequestWrapper(HttpServletRequest request,
AuthenticationTrustResolver trustResolver, String rolePrefix) {
super(request, trustResolver, rolePrefix);
}
#Override
public boolean isUserInRole(String role) {
return true;
}
When the application is run, the new bean does not take the place of the existing SecurityContextHolderAwareRequestWrapper class. This is clear because when the new class is instantiated, the constructor is not injected with the beans being injected into SecurityContextHolderAwareRequestWrapper. The application fails to start because parameters of type AuthenticationTrustResolver and String to the new class MySecurityContextHolderAwareRequestWrappercould could not be found
What is the correct way to override SecurityContextHolderAwareRequestWrapper, or for that matter any class in the Spring Boot framework?
Thanks
The SecurityContextHolderAwareRequestWrapper class is ultimately used by the SecurityContextHolderAwareRequestFilter configured with http.servletApi(). Some information about this feature is available in the Spring Security reference docs.
This feature shields you from direct dependence on Spring Security and provides very high level integration with Spring Security through the Servlet API. You cannot directly influence the class used to wrap the request.
However, if you wish to temporarily modify the result of role checks, you can influence what roles are available in the Authentication object during authentication itself. See info in the docs on GrantedAuthority, and note that you will want to customize roles during authentication by providing a custom UserDetailsService.
We are using OAuth2 for securing our REST endpoints. Nearly all of our endpoints require authentication. We have couple of public endpoints. We configure spring security using #EnableWebSecurity. All the public endpoints are explicitly listed in the configuration (see "publicpath_x" in the example below). Instead of explicitly adding each new public enpodint in the configuration, it would be much easier to have a custom annotation, e.g. #PublicAccess which will designate each public endpoint. Is it possible to configure that endpoints annotated with this annotation will be considered as public, i.e. no authentication will be required? We don't want to designate public endpoints in path (e.g. all public endpoints path will start/end with "/public").
Security configuration:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatchers("publicpath1", "publicpath2").permitAll() //...
}
}
Example public REST controller with custom annotation:
#RestController
public class PublicController1 {
#PublicAccess //our custom annotation
#RequestMapping(value = "publicpath1", method = RequestMethod.GET)
public void publicEndpoint1() {
//...
}
}
I was trying the following classes with no success.
javax.servlet.Filter
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
You can use the #PreAuthorize Annotations as method security
Detail see here
can someone explain me when to use WebSecurityConfigurerAdapter and when UserDetailsService. I just started learning spring security, noticed that extending both interfaces you can create security implementation. But which one I should use if I want to create security for web project connection from angular based site and user data saved in Database.
The components you are talking about have very different responsibilities and therefore the question do I use one or the other? does not really make sense. Take a look at the JavaDocs of those components to learn the difference.
UserDetailsService
Core interface which loads user-specific data. It is used throughout the framework as a user DAO and is the strategy
used by the DaoAuthenticationProvider. The interface requires only one read-only method, which simplifies
support for new data-access strategies.
WebSecurityConfigurerAdapter
Provides a convenient base class for creating a WebSecurityConfigurer instance. The implementation allows customization by overriding methods.
For example you could have security configuration class which extends WebSecurityConfigurerAdapter and uses custom UserDetailsService to load user information like so:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(new ShaPasswordEncoder());
authenticationProvider.setUserDetailsService(userService);
return authenticationProvider;
}
// ...
}
The core components of Spring Security and their responsibilities are also nicely described in the reference guide.
Spring Security has the assumption of Authentication is a Principal.
public interface Authentication extends Principal, Serializable {}
HttpServletRequest has the method of getUserPrincipal which is responsible for accessing principal object.
Let's consider this case:
public interface RealPrincipal extends Principal {
public Integer getId();
}
Common Module A has Real Principal interface and implementation.
Module A uses Common Module A, Servlet Api and does not depend on Spring Security:
Module B uses Common Module A, Servlet Api and configures Spring Security. This module responsible for security and UserDetails implementation.
Web A uses Module A and Module B.
In order to use request methods, I am ending up with such an implementation:
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
This is forcing me to have dependency of Spring Security for the Module A and other modules. I believe that a proper servlet api abstraction should not depend on spring security. request.getUserPrincipal should return real principal.
Please explain why org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper returns
Authentication instead of Real Principal.
Edit: I have added Common Module A to my scenario and updated that Module B is responsible for security.
As Luke stated, Spring Security uses the Authentication for the Principal because it implements Principal. It does not use the Authentication#getPrincipal() because it is not guaranteed to be a Principal (it is an Object). In fact, in most situations Spring Security's Authentication#getPrincipal() returns a User (does not implement Principal), a custom UserDetails provided by users of the framework, or a String.
If you want Spring Security to handle this, you will likely need to implement this logic using an HttpServletRequestWrapper as Luke suggested. For example, you could do the following:
public RealPrincipalFilter extends OncePerRequestFilter {
public void doFiter(HttpServletRequest request, HttpServletResponse response, FilterChain) {
chain.doFilter(new RealPrincipalRequestWrapper(request), response);
}
private static final class RealPrincipalRequestWrapper
extends HttpServletRequestWrapper {
public Principal getUserPrincipal() {
Authentication auth = (Authentication) super.getPrincipal();
return auth == null ? null : (RealPrincipal) auth.getPrincipal()
}
}
}
#Configuration
#EnableWebSecurity
public WebSecurityConfig extends WebSecurityConfigurerAdapter {
public configure(HttpSecurity http) {
http
// ... other config ...
.addFilterAfter(new RealPrincipalFilter(), SecurityContextHolderAwareRequestFilter.class);
}
...
}
Alternatively, take a look at my answer on your other question for options to integrate with Spring MVC - Injecting Custom Principal to Controllers by Spring Security
The short answer is that Authentication is a Principal so that it can be used in APIs (such as the servlet API method you mention) which require one.
What does this mean in practice? Not a lot. Java's Principal interface has only one method getName, so if you want to do more than render the user's name, you need to know something more about the implementation.
You should probably think about what you mean when you use the phrases "real principal" and "proper servlet api abstraction". How would you expect to implement your someRequestHandler method if the principal was a "real" one, for example?