Search code examples
spring-security-rest

How to skip authorization for HAL browser in a spring boot application that make use of spring security


I wanted to allow HAL browser to skip authorization on a spring boot application. I am using Spring Security for authorization.

Here is the snap shot of the entries from build.gradle file

 implementation 'org.springframework.boot:spring-boot-starter-data-rest'
 implementation 'org.springframework.boot:spring-boot-starter-hateoas'
 implementation 'org.springframework.boot:spring-boot-starter-validation'
 implementation 'org.springframework.boot:spring-boot-starter-security'

My Spring boot application runs on port 2128

http://localhost:2128/browser/index.html would open the HAL browser before spring security was implemented. I tried adding .antMatchers("/browser/index.html").permitAll()** in the configure method of SecurityConfiguration class given below. I also tried overriding public void configure(WebSecurity web) method to ignore the URL

Background : HAL Browser was working before I have implemented Spring Security Authorization. It stopped working after spring security was implemented.



        @Configuration
        @EnableWebSecurity
        public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


            @Override
            protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.authenticationProvider(daoAuthenticationProvider());
            }

            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                        .csrf().disable()
                        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                        .and()
                        .addFilter(new AuthorizationFilter(authenticationManager(), userRepository))
                        .authorizeRequests()
                        // configure access rules
                        .antMatchers("/browser/index.html**").permitAll()
                        .anyRequest().authenticated();

                http.headers().frameOptions().disable();
            }

            @Override
            public void configure(WebSecurity web) throws Exception {
                web.ignoring().antMatchers("/browser/index.html");
            }

        }

     


        public class AuthorizationFilter extends BasicAuthenticationFilter {

            public static final String HEADER_STRING_REMOTE_USER = "Remote-User";

            /**
             * Security pipe line is composed of different filters so we need to delegate to the rest of the pipeline.
             *
             * @param request
             * @param response
             * @param chain
             * @throws IOException
             * @throws ServletException
             */
            @Override
            protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

                // Read the Authorization header, where we get the userId
                String userId = request.getHeader(HEADER_STRING_REMOTE_USER);

                // If header does not contain userId or is null delegate to Spring impl and exit
                if (userId == null) {
                    chain.doFilter(request, response);
                    return;
                }

                // If userId is present, try grab user principal from database and perform authorization
                Authentication authentication = getUsernamePasswordAuthentication(userId);
                SecurityContextHolder.getContext().setAuthentication(authentication);

                // Continue filter execution
                chain.doFilter(request, response);
            }

            private Authentication getUsernamePasswordAuthentication (String userId) {

                // Search in the DB if we find the user by userId
                // If so, then grab user details and create spring auth token using username, pass, authorities/roles
                if (userId != null) {
                    List user = userRepository.findByUserId(userId);
                    UserPrincipal principal = new UserPrincipal(user.get(0));
                    UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(principal, null, principal.getAuthorities());
                    return auth;
                }

                return null;
            }
        }

Has anybody experienced similar issues...


Solution

  • What I ended up doing is to manage using spring active profiles.

    For more information on spring profiles see the link

    I enabled Spring Security for "secure" profile and disabled it for "dev" profile. So in "dev" profile HAL browser works without any security interruptions.

    @Configuration
    @EnableWebSecurity
    @Profile("secure")
    public class WebSecurityConfigEnable extends WebSecurityConfigurerAdapter {
    
        @Autowired
        UserPrincipalDetailsService userPrincipalDetailsService;
    
        private UserRepository userRepository;
    
        @Value("${spring.profiles.active}")
        private String activeProfile;
    
            public WebSecurityConfigEnable (UserPrincipalDetailsService 
    userPrincipalDetailsService, UserRepository userRepository) {
            this.userPrincipalDetailsService = userPrincipalDetailsService;
            this.userRepository = userRepository;
        }
    
        @Override
        protected void configure (AuthenticationManagerBuilder auth) throws 
    Exception {
            auth.authenticationProvider(daoAuthenticationProvider());
        }
    
        @Override
        protected void configure (HttpSecurity http) throws Exception {
            http
                    .cors().configurationSource(request -> new 
    CorsConfiguration().applyPermitDefaultValues())
                    .and()
                   .csrf().disable()
    
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .addFilter(new AuthorizationFilter(authenticationManager(), 
    userRepository, activeProfile))
                    .authorizeRequests()
                    // configure access rules
                    .anyRequest().authenticated();
        }
    
        @Bean
    DaoAuthenticationProvider daoAuthenticationProvider () {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(this.passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);
    
        return daoAuthenticationProvider;
    }
    
    @Bean
    PasswordEncoder passwordEncoder () {
        return new BCryptPasswordEncoder();
    }
    }
    

    For running the application in "dev" profile

    java -jar -Dspring.profiles.active=dev build\libs\springApp-0.1.1-SNAPSHOT.jar