Not able to access some routes in spring boot - java

This is my admin controllers which i am not able to access
import mis.entity.User;
import mis.services.AdminService;
#Controller
#RequestMapping("/admin/")
public class AdminController {
#Autowired
private AdminService adminService;
#RequestMapping("adduser")
public String adduser() {
return "admin/adduser";
}
#RequestMapping(value = "do_register", method = RequestMethod.POST)
public String registerUser(#ModelAttribute("user") User user) {
System.out.println(user);
adminService.addUser(user);
return "redirect:/admin/adduser";
}}
This is happening after i configured spring security before activating spring security iwas able to access all routes.
#Configuration
#EnableAutoConfiguration
#EnableWebSecurity
public class MyConfig extends WebSecurityConfigurerAdapter {
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/new").hasAnyAuthority("ADMIN", "CREATOR")
.antMatchers("/admin/**").hasAnyAuthority("ADMIN", "EDITOR")
.antMatchers("/delete/**").hasAuthority("ADMIN")
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/403")
;
}}
There is one more controller which i can access.
But i cant access this admincontroller i think that /admin/ is causing problem.
Edited code in MyConfig
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER")
.antMatchers("/**").permitAll().and().formLogin()
.loginPage("/signin")
.defaultSuccessUrl("/home")
.and().csrf().disable();

Related

Cannot configure my SecurityConfig class without deprecated WebSecurityConfigurerAdapter

I have added BCryptPasswordEncoder to my project and I store every user's password in my DB in encoded way. And now I can't log in using not encoded password but if I use encoded password I still can log in. As I know, AuthenticationManager have to encode entered password according to bean PasswordEncoder and compare with each password in my DB.
So the question is: why AuthenticationManager doesn't encode entered password?
P.S: As I know, authenticationConfiguration.getAuthenticationManager() replaces authenticationConfiguration.userDetailsService(personDetailsService).passwordEncoder(getPasswordEncoder()) since Spring Security 5.7.0-M2.
My SecurityConfig class:
#EnableWebSecurity
public class SecurityConfig {
private final PersonDetailsService personDetailsService;
#Autowired
public SecurityConfig(PersonDetailsService personDetailsService) {
this.personDetailsService = personDetailsService;
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests().antMatchers("/auth/login", "/error", "/auth/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/auth/login")
.loginProcessingUrl("/process_login")
.defaultSuccessUrl("/hello", true)
.failureUrl("/auth/login?error")
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/auth/login");
return http.build();
}
#Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
My RegistrationService:
#Service
public class RegistrationService {
private final PeopleRepository peopleRepository;
private final PasswordEncoder passwordEncoder;
#Autowired
public RegistrationService(PeopleRepository peopleRepository, PasswordEncoder passwordEncoder) {
this.peopleRepository = peopleRepository;
this.passwordEncoder = passwordEncoder;
}
#Transactional
public void register(Person person) {
person.setPassword(passwordEncoder.encode(person.getPassword()));
peopleRepository.save(person);
}
}
EDIT:
If I extend my SecurityConfig from deprecated WebSecurityConfigurerAdapter and change my code to this:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final PersonDetailsService personDetailsService;
#Autowired
public SecurityConfig(PersonDetailsService personDetailsService) {
this.personDetailsService = personDetailsService;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests().antMatchers("/auth/login", "/error", "/auth/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/auth/login")
.loginProcessingUrl("/process_login")
.defaultSuccessUrl("/hello", true)
.failureUrl("/auth/login?error")
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/auth/login");
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(personDetailsService).passwordEncoder(getPasswordEncoder());
}
}
then it works like it have to (entered by user password is getting encrypted by configure(AuthenticationManagerBuilder auth) and then it compares to other passwords from DB and if there is the same password found user is authenticated).

Periodically the retrieved user from the spring security context is empty

I have spring web mvc project with Spring Security 4.1.0.RELEASE
In spring controller i try fetch the user from the context
#RestController
public class Test {
#RequestMapping(value="test", method = RequestMethod.POST)
public ResponseEntity<Void> test() {
ContextUser user = (ContextUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
user is an instance with id = 0, login = null .... It is empty instance.
org.springframework.security.core.Authentication isAuthenticated = true, list of Collection<? extends GrantedAuthority> are correct This behaviour is occurred periodically. It is not every time for this request. I catch this issue only for that request
My configurations
#Configuration
#ComponentScan(basePackages={"com.test.app"},
excludeFilters=#ComponentScan.Filter(type=FilterType.REGEX, pattern={"com.test.app.web.*"}))
#PropertySource(value = { "classpath:application.properties" })
#EnableAspectJAutoProxy
public class AppConfig {
#Autowired
private DataSource dataSource;
//My beans
}
#Component
public class TestUserDetailsService implements UserDetailsService{
#Autowired
private TestUserService service;
#Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
User user = service.findByLogin(userName);
if (user == null) {
throw new UsernameNotFoundException("Error");
}
return new ContextUser(user);
}
}
public class ContextUser extends User implements UserDetails {
//...
}
#Configuration
#EnableWebSecurity
#EnableAsync
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private TestAuthenticationEntryPoint testAuthenticationEntryPoint;
#Autowired
private TestSimpleUrlAuthenticationSuccessHandler testSimpleUrlAuthenticationSuccessHandler;
#Autowired
private TestSimpleUrlAuthenticationFailureHandler testSimpleUrlAuthenticationFailureHandler;
#Autowired
private LogoutSuccessHandler logoutSuccessHandler;
#Autowired
private TestUserDetailsService testUserDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder registry) throws MyException {
registry.userDetailsService(testUserDetailsService).passwordEncoder(new TestEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(testAuthenticationEntryPoint)
.and().sessionManagement().sessionFixation().migrateSession().maximumSessions(-1).sessionRegistry(sessionRegistry()).and()
.and()
.authorizeRequests()
.antMatchers("/").access("hasAuthority('TEST')")
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(testSimpleUrlAuthenticationSuccessHandler)
.failureHandler(testSimpleUrlAuthenticationFailureHandler)
.and()
.logout().logoutSuccessHandler(logoutSuccessHandler)
.and()
.headers().cacheControl().disable().frameOptions().sameOrigin();
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/resources/**");
}
}
Are any ideas why this behaviour is happened?

How to mock custom UserServiceDetails in SpringSecurity Bean for unit-testing?

I have Spring Boot application with basic auth enabled. UserServiceDetails consumed from DB. For the unit-testing purpose, I want to mock it, so the data will be consumed from elsewhere.
How can I do it?
My question is not how to mock UserServiceDetails itself but how to mock the way that I can use it to test Controllers with basic auth.
The below is my SpringSecurity config:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_WHITELIST = {
// -- swagger ui
"/",
"/csrf",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**"
};
#Autowired
#Qualifier("customUserDetailsService")
private UserDetailsService userDetailsService;
private final static Integer bCryptEncryptionLevel = 8;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder(bCryptEncryptionLevel);
}
public SecurityConfig() {
super();
}
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(authenticationProvider());
authManagerBuilder.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
return authenticationProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
// allow default swagger docket
.regexMatchers("\\A/v2/api-docs\\Z").permitAll()
// require auth for any other swagger docket
.regexMatchers("\\A/v2/api-docs?.*\\Z").authenticated()
.antMatchers("/**").authenticated()
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
To summarize, how can I mock UserServiceDetails into SpringSecurity config, so I can unit-test controllers into my Spring Boot app?
I think you should use #Profile, UserDetailesService is an interface creates two implementation of UserDetailesService, one for test and another for the rest of the case
#Component
#Profile("test")
public class UserDetailesServiceTestImpl implements UserDetailesService{
}
#Component
#Profile("!test")
public class UserDetailesServiceImpl implements UserDetailesService{
}

Problem with permitAll in Vaadin and WebSecurity - not working

I have few views made in Vaadin by #Route and now I want to add Security and some Login. In my SecurityConfiguration class I'm setting antMatchers.permitAll() only for 2 views and for the rest with Role ADMIN. But it is not working as I think it should. It demands login to access every view, and after login I have access to all views no matter what role has the user.
I hoped this tutorial will help me, but in there are no views accessible without login.
Securing Your App With Spring Security
My configuration class:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private UserService userService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public SecurityConfiguration(UserService userService) {
this.userService = userService;
}
#Autowired
private void configureAuth(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
auth.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder().encode("user"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and()
.anonymous()
.and()
.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.antMatchers("/recipe-manager", "/ingredient-manager").hasAnyRole("ADMIN")
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().logoutSuccessUrl("/")
.and()
.csrf().disable().cors().disable().headers().disable();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/VAADIN/**",
"/favicon.ico",
"/robots.txt",
"/manifest.webmanifest",
"/sw.js",
"/offline-page.html",
"/icons/**",
"/images/**",
"/frontend/**",
"/webjars/**",
"/h2-console/**",
"/frontend-es5/**", "/frontend-es6/**");
}
}
My Views have annotations like:
#Route("recipe-manager")
public class RecipeManagerView extends VerticalLayout
#Route("")
public class RecipeBrowserView extends VerticalLayout
#Route("login")
public class LoginView extends VerticalLayout
#Route("ingredient-manager")
public class IngredientManagerView extends VerticalLayout
I would expect that anyone can have access to RecipeBrowserView and LoginView, but only logged user can have access to RecipeManagerView and IngredientMangerView.
You cannot use path based matching from Spring Security for Vaadin routes. Spring Security does the matching based on request paths whereas navigation from one view to another inside Vaadin is sent as metadata inside an internal request that always goes to the same hardcoded path.
Instead, you can implement your access control logic in an interceptor provided by Vaadin. You can have a look at https://vaadin.com/tutorials/securing-your-app-with-spring-security to find out more about this.
To my understanding antMatchers only accept single arguments. You should change you configuration class like:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private UserService userService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public SecurityConfiguration(UserService userService) {
this.userService = userService;
}
#Autowired
private void configureAuth(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
auth.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder().encode("user"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and()
.anonymous()
.and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/recipe-manager", "/ingredient-manager").hasAnyRole("ADMIN")
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().logoutSuccessUrl("/")
.and()
.csrf().disable().cors().disable().headers().disable();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/VAADIN/**",
"/favicon.ico",
"/robots.txt",
"/manifest.webmanifest",
"/sw.js",
"/offline-page.html",
"/icons/**",
"/images/**",
"/frontend/**",
"/webjars/**",
"/h2-console/**",
"/frontend-es5/**", "/frontend-es6/**");
}
}

Oauth2 Resource server overlap Spring Security configuration

I am trying to configure Spring Security and OAuth2 on java config. I am using Spring Security version 4.0.4.RELEASE and OAuth2 version 2.0.11.RELEASE.
Spring Security config works well. Also I can get an access token with OAuth2 AuthorizationServer, but my ResourceServer does not work correctly. When I set the annotation #EnableResourceServer I can only check my access token and other URLs I cannot open (Security configuration and AuthorizationServer configuration do not work). I see the following error:
<oauth>
<error_description>
An Authentication object was not found in the SecurityContext
</error_description>
<error>unauthorized</error>
</oauth>
If I remove an annotation #EnableResourceServer, my ResourceServer does not check an access token. It just redirects to the authentication page.
This is my code:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class GlobalSecurityConfig extends GlobalMethodSecurityConfiguration {
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
#Qualifier("authUserDetailsService")
private UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Autowired
#Qualifier("permissionEvaluator")
private PermissionEvaluator permissionEvaluator;
#Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setDefaultRolePrefix("");
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return expressionHandler();
}
}
SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean(name = "clientAuthenticationEntryPoint")
public OAuth2AuthenticationEntryPoint oauthAuthenticationEntryPoint() {
OAuth2AuthenticationEntryPoint entry = new OAuth2AuthenticationEntryPoint();
entry.setRealmName("myapp/client");
entry.setTypeName("Basic");
return entry;
}
#Autowired
#Qualifier("webExpressionHandler")
private DefaultWebSecurityExpressionHandler expressionHandler;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/html/**", "/webapi/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/admin/**", "/**")
.and()
.authorizeRequests()
.expressionHandler(expressionHandler)
.antMatchers("/admin/**").access("hasRole('ADMINISTRATOR')")
.antMatchers("/1/admin/**").access("hasRole('ADMINISTRATOR')")
.antMatchers("/profile**").authenticated()
.antMatchers("/oauth/authorize").authenticated()
.and()
.formLogin().loginPage("/login")
.failureUrl("/login?error=1")
.loginProcessingUrl("/login-attempt")
.defaultSuccessUrl("/", false)
.and()
.sessionManagement()
.sessionFixation().migrateSession()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.exceptionHandling()
.accessDeniedPage("/access-denied")
.and()
.csrf();
}
}
Oauth config:
#Configuration
public class Oauth {
#Configuration
#EnableResourceServer
public static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_oauth_server";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.regexMatchers("/api/v0/.*").authenticated()
.antMatchers("/**").denyAll()
;
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private AuthorizationCodeServices verificationCodeService;
#Autowired
#Qualifier("clientDetails")
private ClientDetailsService clientDetailsService;
#Autowired
#Qualifier("tokenStore")
private TokenStore tokenStore;
#Bean(name = "tokenServices")
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetailsService);
return tokenServices;
}
#Bean
public ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter() throws Exception {
ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
filter.setAuthenticationManager(authenticationManager);
return filter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.authorizationCodeServices(verificationCodeService);
endpoints.tokenServices(tokenServices());
endpoints.reuseRefreshTokens(true);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()");
oauthServer.checkTokenAccess("permitAll()");
oauthServer.realm("myapp/client");
oauthServer.addTokenEndpointAuthenticationFilter(clientCredentialsTokenEndpointFilter());
oauthServer.allowFormAuthenticationForClients();
}
}
}
So, ResourceServer config overlap other configuration. How can I fix it? I would be thankful for any help.
I see that you want to protect some endpoints with an access token, and other endpoints with normal form login.
Can you try restricting the applicability of your ResourceServerConfiguration to apply only to certain endpoints by something like: http.requestMatcher(new AntPathRequestMatcher("/api/v0/**")).... Do the same for SecurityConfig but for the endpoints you want it to take care of.

Categories

Resources