Can't use post method of any controller after adding facebook social in my Spring Boot - spring

The controller has #RequestMapping("/api")
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/users" ,"/api/books/{id}","/api/authors", "/api/books","/api/categories").permitAll()
.anyRequest().authenticated()
.and().logout().logoutUrl("/logout")
.logoutSuccessUrl("/");
}
Get methods work perfect, but Post doesn't work on the same url's.
Here is an example from one GET and one POST method.
#PostMapping("/users")
User createUser(#RequestBody User user){
return this.userRepository.save(user);
}
#GetMapping("/users")
Collection<User> getUsers(){
return this.userRepository.findAll();
}
So, GET is working, but POST not.
Post method redirect me to facebook login

I solved it by adding the following line
.csrf().disable() at the beginning of the configure method

Related

Pom.xml file dependencies not found

When I try to check my spring registration request, it should return the message "it Works," but I get nothing. Does anyone have any ideas what might be wrong?
I had missed an API link in the.antMatchers section of the WebSecurityConfig file.
If you preview your postman response you can see a login form which means you are not authenticated. If your signup request does not need any authentication you can simply exclude your registration api endpoint from spring checks. To do that permit all requests to the particular url in your configuration file
If you are using WebSecurityConfigurerAdapter, add an antMatcher entry to your configure method.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/v1/registration").permitAll()
.anyRequest().authenticated();
}
Since WebSecurityConfigurerAdapter is deprecated now if you want to use SecurityFilterChain you can do it as follows. For more info refer documentation.
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/v1/registration").permitAll()
.anyRequest().authenticated();
return http.build();
}

spring security implementation to secure REST APIs in my spring boot project

I have a RestController which has one API that is used to authenticate a user. I want this API to be accessible by anyone whether authenticated or not and irrespective of their roles. In other words, this API should be called when someone types in their username and password and presses submit button.
Here is the config(HttpSecurity http) method of security config java file
#Override
protected void configure(HttpSecurity http) throws Exception {
http/* .csrf().disable() */
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/customer/**").hasRole("CUSTOMER")
.antMatchers("/supplier/**").hasRole("SUPPLIER")
.antMatchers("/user/authenticate").permitAll()
.antMatchers("/user/**").authenticated()
.and()
.formLogin().permitAll()
.and()
.logout()
.permitAll();
}
In the above code, I've written ''antMatchers("/user/authenticate").permitAll()'' because I want this url to be accessible by everyone and whatever logic is written in the controller should be executed.
And here is my controller
#RestController
#RequestMapping("/user")
public class AuthenticationController {
#Autowired
private AuthenticationManager authenticationManager;
#PostMapping("/authenticate")
public void authenticate(#RequestBody AuthenticationRequest request) {
Authentication token = authenticationManager.authenticate(new
UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
// more code
}
}
But I don't know why it is not working. When I send a POST request from POSTMAN, I get the following response back:
{
"timestamp": "2020-07-24T08:50:02.514+00:00",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/user/authenticate"
}
Someone please suggest what I should do to make it hit my REST controller

How do I get the right user principal with Spring-Boot and Oauth2?

I am practising Spring-Boot 2.2 + Spring Security 5 + Oauth2. Following a lot of examples I am hitting a wall here.
My spring security configuration is this:
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/css/**", "/webjars/**").permitAll()
.anyRequest().authenticated()
.and().oauth2Login().userInfoEndpoint()
.userService(new DefaultOAuth2UserService());
}
and I have a controller with this method:
#GetMapping("/create")
public ModelAndView create(Principal principal) {
log.debug(principal);
return new ModelAndView("create.html", "topicForm", new TopicForm());
}
in the Thymeleaf template I would call <span sec:authentication="name">User</span>, and it only returns a number.
in debug, authentication is org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken, and the Principal is a DefaultOidcUser, the name attribute is "sub", which is not a name but a number in google's oauth response.
DefaultOAuth2UserService is never called before my breakpoint hits in the controller.
Where did I take the wrong turn?
--edit--
In further debugging, I think the problem stems from OAuth2LoginAuthenticationFilter calling org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService which would be configurable by oidcUserService(oidcUserService())
To get current principal you can use #AuthenticationPrincipal annotation which resolves Authentication.getPrincipal() so you can add it as argument.
public ModelAndView create(#AuthenticationPrincipal Principal principal) {
log.debug(principal);
return new ModelAndView("create.html", "topicForm", new TopicForm());
}
You can make use of the SecurityContextHolder.
public ModelAndView create() {
Object principal = SecurityContextHolder.getContext().getAuthentcation().getPrincipal();
log.debug(principal);
return new ModelAndView("create.html", "topicForm", new TopicForm());
}

Spring Security OAuth - how to disable login page?

I want to secure my application with Spring Security, using OAuth 2. However, I don't want the server to redirect incoming unauthorized requests, but instead to respond with HTTP 401. Is it possible?
Example: this code redirects requests to a default login page.
application.properties
spring.security.oauth2.client.registration.google.client-id=...
spring.security.oauth2.client.registration.google.client-secret=...
AuthConfig.java
#Configuration
public class AuthConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.oauth2Login();
// https://stackoverflow.com/questions/31714585/spring-security-disable-login-page-redirect
// deos not work
// .and()
// .formLogin().successHandler((request, response, authentication) -> {});
}
}
You need to create new authentication entry point and set it in configuration.
#Configuration
public class AuthConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/secured/**").authenticated()
.anyRequest().permitAll()
.and()
.oauth2Login();
}
}
public class AuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AuthenticationEntryPoint() {
super("");
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(401, "Unauthorized");
}
}
You need to set oauth2Login.loginPage in your HttpSecurity config and create a controller mapping to return whatever you want. Here's a simple example.
So in your security config
http
.authorizeRequests()
.antMatchers("/noauth").permitAll()
.oauth2Login()
.loginPage("/noauth")
In a controller
#GetMapping("/noauth")
public ResponseEntity<?> noAuth() {
Map<String, String> body = new HashMap<>();
body.put("message", "unauthorized");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(body);
}
You can pass a map or pojo to the body method.
I would like to expand on Petr's answer by explaining that apparently for the time being first of all, the default login page is shown when there are more than one OAuth2 configured providers. I would expect that Spring Boot would have a smart trick to bypass this page easily and choose the right provider automatically, basing e.g. on the existence of the provider's client ID in the original request. I found out the hard way that this is not the case. So the way to do this is.. this not very apparent trick of providing a custom handler for failures - that will REDIRECT the user to the correct OAuth2 endpoint for each provider, based on the original HTTP request URL. I tried this and it works and I spent a whole day trying all manners of other solutions - my original scenario was to pass additional parameters to OAuth2 scheme in order to be able to get them back on successful authentication - they used to do this appending Base64 encoded information to the "state" URL request parameter, but Spring Security does not allow this at the moment. So the only alternative was to call a Spring Security-protected URL with those parameters already there, so when the successful authentication happens, this URL is accessed again automatically with those parameters intact.
Related: Multiple Login endpoints Spring Security OAuth2

How to avoid redirecting to login form for some URL with Spring Security?

This is the Spring Security configuration of my webapp
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", LOGIN, "/webjars/**").permitAll()
.antMatchers(CONFIGURATION).hasAuthority(Authorities.AUTHORITY_SOLMAN72_EXPORT_ENABLED.getKey())
.antMatchers("/api/**").hasAuthority(Authorities.AUTHORITY_SOLMAN72_EXPORT_ENABLED.getKey())
.and()
.formLogin()
.loginPage(LOGIN)
.and()
.addFilterBefore(oAuth2ClientAuthenticationProcessingFilter, BasicAuthenticationFilter.class);
}
Currently the server is redirecting to the LOGIN page every request that does not have the right credentials.
I want to redirect to the LOGIN page only the unauthorized requests to CONFIGURATION, while the unauthorized requests to /api/** should answer with 403.
What's a good way of achieving that?
I solved my problem using an AuthenticationEntryPoint:
http
.authorizeRequests()
.antMatchers(LOGIN).permitAll()
.antMatchers("/**").hasAuthority(Authorities.AUTHORITY_SOLMAN72_EXPORT_ENABLED.getKey())
.and()
.addFilterBefore(oAuth2ClientAuthenticationProcessingFilter, BasicAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(unauthenticatedRequestHandler);
#Bean
UnauthenticatedRequestHandler unauthenticatedRequestHandler() {
return new UnauthenticatedRequestHandler();
}
static class UnauthenticatedRequestHandler implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
if (request.getServletPath().startsWith("/api/")) {
response.setStatus(403);
} else {
response.sendRedirect(LOGIN);
}
}
}
You could use DelegatingAuthenticationEntryPoint:
An AuthenticationEntryPoint which selects a concrete AuthenticationEntryPoint based on a RequestMatcher evaluation.
with Http403ForbiddenEntryPoint for /api/** and LoginUrlAuthenticationEntryPoint as default entry point.
#Bean
public DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint() {
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher, AuthenticationEntryPoint>();
entryPoints.put(new AntPathRequestMatcher("/api/**"), new Http403ForbiddenEntryPoint());
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
defaultEntryPoint.setDefaultEntryPoint(new LoginUrlAuthenticationEntryPoint(LOGIN));
return defaultEntryPoint;
}
I went to implement dur's answer but noticed there's a ExceptionHandlingConfigurer.defaultAuthenticationEntryPointFor(...) (available from around Spring Security 3.2.x) which does effectively the same thing with much less dependent code:
http.exceptionHandling()
.defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), new AntPathRequestMatcher("/api/**"));
Moreover, I noticed specifying any defaultAuthenticationEntryPointFor() sets the first up as the default entry point.
By default, FormLoginConfigurer, OAuth2LoginConfigurer, Saml2LoginConfigurer, etc. adds their own during SecurityConfigurer.init() and, unless we've specified one, the first among those becomes the default entry point.
This may or may not be useful, but because the
AuthenticationEntryPoint provided by FormLoginConfigurer, OAuth2LoginConfigurer, Saml2LoginConfigurer, etc. avoids requests containing the header X-Requested-With: XMLHttpRequest, the entry point we've specified with defaultAuthenticationEntryPointFor() will end up being used for AJAX, regardless of what we've specified for the request matcher argument.

Resources