Authentication in Spring Web Security issue - spring

I am going to set up background Spring Authentication by a custom class that implemented UserDetailsService. As said in the documentation method loadUserByUsername calls each time when user try to login, but it don't in the case below.
#Component
public class AuthenticationUserDetailsService implements UserDetailsService {
#Autowired
private PersonRepository personRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Person> personByUserName = personRepository.findPersonByUserName(username);
Person person = personByUserName.
orElseThrow(() -> new UsernameNotFoundException("User with username has not found"));
return new User(username, person.getPassword(), Collections.emptyList());
}
}
I try to use several alternatives to set up configure(HttpSecurity http) method in WebSecurityConfig class.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("api/person/login")
.usernameParameter("username")
.passwordParameter("password");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/index.html", "/", "/home", "/api/person/login").permitAll()
.anyRequest().authenticated();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.
authorizeRequests().
anyRequest().authenticated()
.and().
formLogin().
loginProcessingUrl("/login").
usernameParameter("username").
passwordParameter("password");
}
Registration DaoAuthenticationProvider:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getAuthenticationProvider());
}
#Bean
public DaoAuthenticationProvider getAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(authenticationUserDetailsService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
return daoAuthenticationProvider;
}
Could anyone explain, where is error, and why loadUserByUsername method doesn't call at all?
The Angular 8 UI part uses to login.
public loginPerson(person: Person): Observable<Person> {
let url = "http://localhost:8080/login";
return this.httpClient.post<Person>(url, {userName: person.username, password: person.password});
}

Related

SpringSecurity: hasRole does not work after set config?

this is my Java Config:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("Jon")
.password("123456")
.roles("USER")
.and()
.withUser("Bob")
.password("qwer")
.roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers(HttpMethod.GET,"/admin/**").access("hasRole('ADMIN')")
.anyRequest().authenticated()
.and()
.httpBasic()
;
}
}
As you can see, I hava to peroson
Jon, has role as USER
Bob, has roles as USER ADMIN
But, so Jon should not hava permition to visis /admin/**, then I write follow test
ResultMatcher isUnauthorized = MockMvcResultMatchers.status()
.is(401);
String credential = Base64.getEncoder().encodeToString("Jon:123456".getBytes());
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.get("/admin/")
.header("Authorization", "Basic " + credential);
mockMvc.perform(builder)
.andDo(MockMvcResultHandlers.print())
.andExpect(isUnauthorized);
I expect this test return 401 unauthorized, But actually it return 200.
What is the problem?
SpringSecurityVersion is 5.1.5.RELEASE

Spring security AuthenticationServiceException converted to InsufficientAuthenticationException

I've a problem with exception handling during authentication using Spring Security.
This is my AuthenticationProvider where on every exception an AuthenticationServiceException is thrown.
#Component
public class MyAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
// ...
} catch (Exception e) {
throw new AuthenticationServiceException(e.getMessage(), e);
}
}
}
Below my custom AuthenticationProvider.
#Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
log.debug(e.toString());
}
}
This is the security config
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint);
}
}
Everything is triggered as expected. The problem is that in the AuthenticationProvider the AuthenticationException is an instance of InsufficientAuthenticationException and not AuthenticationServiceException as thrown by the AuthenticationProvider.
What I want instead in MyAuthenticationEntryPoint is the exception thrown with the cause set, which is a custom exception.
How can I solve this?
Why Spring replace an AuthenticationServiceException with an InsufficientAuthenticationException?
Thanks in advance.
SOLUTION
I found the solution! The problem is in SecurityConfig class. .authenticationEntryPoint(authenticationEntryPoint) must be under .httpBasic() and not set globally.
The right configuration is the following:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf().disable();
}

Multiple user details services for different endpoints

I am building a REST API using Spring and am currently authenticating all my requests using a custom user details service and this configuration code:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
I am also setting up a DaoAuthenticationProvider to use the my user details service and using that to configure global security.
Now, I want to provide an endpoint that (while still secured with HTTP basic authentication) uses a different user details service to check whether the user is allowed to access the given resource.
How do I use two different user details services for different endpoints?
One thing you can do is have two WebSecurityConfigurerAdapters:
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE)
class FirstEndpointConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) {
http
.requestMatchers()
.antMatchers("/specialendpoint")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.userDetailsService(/* first of your userDetailsServices */);
}
}
#Configuration
class SecondEndpointConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) {
http // all other requests handled here
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.userDetailsService(/* second of your userDetailsServices */);
}
}
requestMatchers() exists for targeting springSecurityFilterChains to specific endpoints.
EDIT: Mahmoud Odeh makes a good point that if the user bases are the same, then you may not need multiple UserDetailsService instances. Instead, you can use one change that isolates your special endpoint by an authority on the user's account:
http
.authorizeRequests()
.antMatchers("/specialendpoint").hasAuthority("SPECIAL")
.anyRequest().authenticated()
.and()
.httpBasic();
Then, your single UserDetailsService would look up all users. It would include the SPECIAL GrantedAuthority in the UserDetails instance for users who have access to /specialendpoint.
I am trying to follow the solution given by M. Deinum but in my case it always goes to the same user service (v2userDetailsService) regardless of which URL is executed /v3/authorize/login or /v2/authorize/login. Here is my code:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration {
#Configuration
#Order(2)
public static class V2Configuration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("v2userDetailsService")
private UserDetailsService v2userDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder(256);
auth
.userDetailsService(v2userDetailsService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and().csrf().disable().headers()
.frameOptions().disable().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/app").permitAll()
.antMatchers("/v2/authorize/login").permitAll()
.antMatchers("/v2/authorize/reLogin").permitAll()
.antMatchers("/v2/authorize/logout").permitAll();
}
}
#Configuration
#Order(1)
public static class V3Configuration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("v3UserDetailsService")
private UserDetailsService v3UserDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder(256);
auth
.userDetailsService(v3UserDetailsService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and().csrf().disable().headers()
.frameOptions().disable().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/v3/authorize/login").permitAll()
.antMatchers("/v3/authorize/reLogin").permitAll()
.antMatchers("/v3/authorize/logout").permitAll();
}
}
}

Spring Security using Oauth | Overriding HttpSecurity

I am Implementing Spring Security using Oauth following these websystique , baeldung,What I found WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter both provides control over HttpSecurity,and filterchain adds them in order 0 and 3 respectively.
So I am overriding configure of any of the above ConfigurerAdapter but only one at a time.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.requestMatchers().antMatchers("/api/**").and()
.authorizeRequests()
.antMatchers("/api/ads").permitAll()
.antMatchers("/api/admin").hasAuthority(RoleConstant.ADMIN.getRole())
.antMatchers("/api/user").hasAuthority(RoleConstant.USER.getRole())
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
What I observe in case of WebSecurityConfigurerAdapter I am able to access unauthorized resources ie I am able to access /api/user after being authenticated even with token having authority ADMIN.Why so?
Note : I am not overriding HttpSecurity of ResourceServerConfigurerAdapter.
References : There are similar resources available here. Resource1 , Resource2.
Also I want to know,I must have to override both configure(HttpSecurity http) or any of the class is sufficient?If yes,which one is recommended?
ResourceServer :
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_rest_api";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.requestMatchers().antMatchers("/api/**").and()
.authorizeRequests()
.antMatchers("/api/ads").permitAll()
.antMatchers("/api/admin").hasAuthority(RoleConstant.ADMIN.getRole())
.antMatchers("/api/user").hasAuthority(RoleConstant.USER.getRole())
.antMatchers("/api/readProperty").access("hasRole('ADMIN')")
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
SpringSecurityConfig :
#Configuration
#EnableWebSecurity
#ComponentScan(basePackages = {"com.ttnd.mvc_mod.services","com.ttnd.mvc_mod.repository","com.ttnd.mvc_mod.config","com.ttnd.mvc_mod.custom"})
#Import({SpringORMHibernateSupportConfig.class})
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
private CustomAuthenticationProvider authProvider;
/* #Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.requestMatchers().antMatchers("/**").and()
.authorizeRequests()
.antMatchers("/oauth/token","/api/ads").permitAll()
.antMatchers("/api/admin").hasAuthority(RoleConstant.ADMIN.getRole())
.antMatchers("/api/user").hasAuthority(RoleConstant.USER.getRole())
.antMatchers("/api/readProperty").access("hasRole('ADMIN')")
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());//.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
}
*/
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.userDetailsService(customUserDetailsService);
auth.authenticationProvider(authProvider);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
#Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
#Bean
#Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}

Authorization roles Spring-boot Oauth2 ~ Restful API

i'm needing help with this problem...
i can't secure my controllers in my security configuration files. but i can do it in my controller using
#PreAuthorize("hasAuthority('ROLE_ADMIN')")
but this is really annoying, i want to do it from my security conf. files
this is my WebSecurityconfigurerAdapter:
#Configuration
//#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = false)
//#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
//#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
CustomUserDetailsService cuds;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(cuds)
.passwordEncoder(passwordEncoder())
.and()
.authenticationProvider(customAuthenticationProvider);
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").authenticated()
.antMatchers("/test").authenticated()
.antMatchers("/usuarios/**").hasRole("ADMIN");
}
}
and this is my Oauth2Configuration:
#Configuration
public class Oauth2Configuration {
private static final String RESOURCE_ID = "restservice";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
// Logout
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
//Session management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//URI's to verify
.authorizeRequests()
.antMatchers("/oauth/logout").permitAll()
.antMatchers("/**").authenticated()
.antMatchers("/usuarios/**").hasRole("ADMIN");
}
}
i've tried to use authority and roles, but nothings works. some idea what i'm doing wrong?
Well thanks to Yannic Klem i got the answer, was a problem with the order
First on my WebSecurityConfigurerAdapter i set my authentication on "usuarios"
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/usuarios").authenticated();
}
after that in my Oauth2Configuration set my authorizarion with my rol.
#Override
public void configure(HttpSecurity http) throws Exception {
http
// Logout
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
//Session management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//URI's to verify
.authorizeRequests()
.antMatchers("/oauth/logout").permitAll()
.antMatchers("/usuarios/**").hasRole("ADMIN");
}
and now all works pretty fine. thank you all!

Resources