I have the following security adapter for my Spring REST service to use HTTP basic http auth.
Right now, when I try to send a request to any GET HTTP endpoint, the request is successfully authorized and processed. But all other HTTP methods are returning 401. Any idea?
#EnableWebSecurity
public class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("USER").and().httpBasic();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
You have an AuthenticationException which is a runtime exception. Read about it here Spring Security Authentication.
The default configuration of WebSecurity, as said here HttpSecurity is:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
Try to add .anyRequest().authenticated() to your code.
Related
Now there is authentication only once when I open my browser. I want to authenticate each request without need to reopen the browser.
This is my configuration class. What can I add to configure function?
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().csrf().disable().httpBasic();
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("").password("{noop}").roles("ADMIN");
}
}
I am getting started with Spring Web Security for my application and I am trying to implement stateless JWT authentication. Curretly, the configure method in the Web Security config is the following
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login", "/register", "/authenticate/{uuid}").permitAll()
.anyRequest().authenticated()
;
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
My jwtAuthenticationEntryPoint is the following:
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
log.warn("Responding with unauthorized error. Message - {}", authException.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Sorry, You're not authorized to access this resource.");
}
}
The authentication works correctly besides for the "/authenticate/{uuid}" endpoint. The request is allowed (Status 200 and correct return of the function) but I keep getting the warning from the jwtAuthenticationEntryPoint class ("Responding with unauthorized error") in the console.
Why is the EntryPoint getting triggered for that specific request and how can I resolve it?
EDIT:
AuthenticationController:
#RestController
#CrossOrigin
public class AuthenticationController {
#RequestMapping(value = "/authenticate/{uuid}", method = RequestMethod.GET)
public ResponseEntity<?> authenticate(#PathVariable String uuid){
return ResponseEntity.ok(uuid);
}
}
Pls use web.ignoring() to try as the below:
public void configure(WebSecurity web) throws Exception {
String [] notauthlist = new String[]{"/login", "/register","/authenticate/**"};
web.ignoring().antMatchers(notauthlist);
}
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests().anyRequest().authenticated()
;
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
I have seen a lot of posts on the same problem, but no solution worked for me.
I have an API secured with spring security as below.
#EnableWebSecurity
#Component
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired private UserService userService;
public SecurityConfiguration() {
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/actuator/shutdown", "/api/register");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I need endpoints /api/register and /actuator/shutdown available without authentication. But, as it turned out, all the endpoints are returning the same 401 status code.
try with this.
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
//no authentication needed for these context paths
.authorizeRequests()
.antMatchers("/your Urls that dosen't need security/**").permitAll()
We implemented a similar approach as mentioned by Supun Above,
http
.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
.anyRequest().authenticated()
.and().httpBasic()
You can keep 'AUTH_WHITELIST' as below to keep adding multiple Endpoints
private static final String[] AUTH_WHITELIST = {
// -- swagger ui
"/api/register",
"/actuator/shutdown"
};
Why following basic security configurations do not apply inMemoryAuthentication() clause?
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.anyRequest().authenticated();
super.configure(http);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("username").password("password");
super.configure(auth);
}
}
After the application initialization, there is still only default user generated by Spring itself, there is no such user like username.
Do not call super method from void configure(AuthenticationManagerBuilder auth). It sets disableLocalConfigureAuthenticationBldr flag to true that leads to your AuthenticationManagerBuilder being ignored. Finally your void configure(AuthenticationManagerBuilder auth) method should look like this:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("username").password("password").roles("USER");
}
In spring boot 2.x, you will have to implement your own UserDetailsService, as described here and here
Example:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger log = LogManager.getLogger();
#Override
protected void configure(HttpSecurity http) throws Exception {
// Note:
// Use this to enable the tomcat basic authentication (tomcat popup rather than spring login page)
// Note that the CSRf token is disabled for all requests
log.info("Disabling CSRF, enabling basic authentication...");
http
.authorizeRequests()
.antMatchers("/**").authenticated() // These urls are allowed by any authenticated user
.and()
.httpBasic();
http.csrf().disable();
}
#Bean
public UserDetailsService userDetailsService() {
// Get the user credentials from the console (or any other source):
String username = ...
String password = ...
// Set the inMemoryAuthentication object with the given credentials:
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
String encodedPassword = passwordEncoder().encode(password);
manager.createUser(User.withUsername(username).password(encodedPassword).roles("USER").build());
return manager;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I have a problem regarding on the controllers request from a spring boot application.
I have made a certificate in order to run the app on https. The certificate works fine, it is valid.
My main problem is when i test my methods from the controller through postman they(the url reques) work fine on https and http...it shouldn't work on http. Can someone help on this ?
This is my WebSecurityConfig class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
public static final String AUTHENTICATED_HEADER_NAME = "Authenticated";
public static final String AUTHENTICATED_TRUE = "true";
public static final String AUTHENTICATED_FALSE = "false";
#Autowired
public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
auth.userDetailsService(authenticationManager).passwordEncoder(passwordEncoder);
}
#Override
#Bean(value = "authenticationManagerBean")
public org.springframework.security.authentication.AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Configuration
#Order(1)
public static class HTTPBasicSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
//todo check how we can change the root url of swagger
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/documentation**", "/configuration/**", "/v2/api-docs**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//todo http basic allows access to all urls after login
http
.httpBasic()
.and()
.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest()
.authenticated();
}
}
#Configuration
#Order(2)
public static class FormLoginSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
//todo more investigation is required to check if it is safe to ignore csrf for login
.ignoringAntMatchers("/login")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.successHandler((httpServletRequest, httpServletResponse, authentication) -> {
httpServletResponse.setHeader(AUTHENTICATED_HEADER_NAME, AUTHENTICATED_TRUE);
})
.failureHandler((httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setHeader(AUTHENTICATED_HEADER_NAME, AUTHENTICATED_FALSE);
httpServletResponse.setStatus(SC_UNAUTHORIZED);
})
.and()
.logout().permitAll()
.and()
.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class)
.addFilterBefore(new CsrfHeaderFilter(), CsrfFilter.class);
http.exceptionHandling().authenticationEntryPoint((HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) -> {
if (authException != null) {
response.setStatus(SC_UNAUTHORIZED);
}
});
}
}
#Configuration
#Order(3)
public static class TestClass extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.httpStrictTransportSecurity()
.includeSubDomains(true)
.maxAgeInSeconds(31536000);
}
}
}
and this is my spring boot version
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
<relativePath></relativePath>
</parent>
Your question is touching on several points:
you can require clients to require secure channels, by adding the security.require_ssl=true configuration property (see the Spring Boot reference documentation about HTTPS)
or use the following configuration snippet http.requiresChannel().anyRequest().requiresSecure();
you might want to enforce that as well with HSTS in Spring Security
None of the above helped the situation I was in.
I figured out that chrome (postman) was automatically transforming my http requests to https.
On the other browsers http requests didn't worked.