I'm trying to use OAuth2 in my spring application.
So here is my pom.xml
Now in Giithub->Profile->Developer, I have created an OAUth application,
the homepage url is : http://localhost:8080/login
And callback url is : http://localhost:8080/datum
So, whenever I run this application(runs at port 8080) and try to access any url child of http://localhost:8080/ it takes me to Login at http://localhost:8080/login, now if I log in, it redirects me to a complex url and instantly to http://localhost:8080/oauth2/authorization/github. After this doesn't matter how much I try, I always get redirected here.
http://localhost:8080/datum is a valid url.
I have added
spring.security.oauth2.client.registration.github.client-id=
spring.security.oauth2.client.registration.github.client-secret=
in application.properties
What is wrong here? What am I missing?
I set the callback url to http://localhost:8080/oauth2/authorization/github, and it solved the problem.
Not sure if it will help, but maybe try adding this:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
Related
After implementing HTTPS in application.properties I can go to the pages specified in my WebSecurityConfigurerAdapter anonymously like I want. However, when I go to a page the requires authorization I get a HTTP ERROR 404 page not found:
"This localhost page can’t be foundNo webpage was found for the web address: https://localhost/login
HTTP ERROR 404".
If I take away the https implementation in application.properties then I can go to the pages I want anonymously and if I go to anything else there is a nice default login form. Why wont this same behavior occur with https implemented????
application.properties:
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:server4.p12
server.ssl.key-store-password=******
server.ssl.key-alias=1
security.require-ssl=true
WebSecurityConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable().authorizeRequests().antMatchers("/", "/save","/success", "/images/**","/css/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
Ok I solved this. I had two issues. The first issue is that I needed to specify an antmatcher for /login/**. Also, my server is running on port 80 in application.properties, so everytime I was going to https://.. the browser sent it over 443 and it wouldn't show up unless I specified https://localhost:80/..
WebSecurityAdapter Configuration:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable().authorizeRequests().antMatchers("/","/login/**", "/save","/success", "/images/**","/css/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
#default server port
server.port=443
#SSL
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:server4.p12
server.ssl.key-store-password=******
server.ssl.key-alias=1
security.require-ssl=true
I encountered the same problem. I was able to fix it by changing server.port=8080 to server.port=8443 in application.yaml.
I am writing a spring boot application in which I am registering a URL to a bean via the SimpleUrlHandlerMapping configuration. Why am I not using the #Controller or #RequestMapping classes to do this ?!! Because I want to dynamically register URL's during runtime.
I am using the following code to register a simple URL to a controller
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MAX_VALUE - 2);
Properties urlProperties = new Properties();
urlProperties.put("/index", "myController");
mapping.setMappings(urlProperties);
return mapping;
}
The above code is working fine, I am able to hit the controller bean registered with the name "myController".
The issue appears when I use spring security. I introduced spring security and configured InMemoryAuthentication, and set my configuration as follows.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index").permitAll()
.anyRequest()
.permitAll();
}
After doing this when I try to access /index path, it throws a 403, forbidden error. I have tried with permitAll() and fullyAuthenticated() configurations. It doesn't seem to work. However, any Controller class registered with the #Controller and #RequestMapping annotations are perfectly working fine with Security.
So, my assumption is that Spring Security is not aware of the dynamically registered URL's via the SimpleUrlHandlerMapping.
How do I solve this ? Is there a way I can tell spring security to include my dynamic URL registrations ? Unable to find any article on this online.
Suggestions and help much appreciated.
UPDATE:
Why csrf().disable() does works
CSRF stands for Cross Site Request Forgery
In simple words, it is one kind of token that is sent with the request to prevent the attacks. In order to use the Spring Security CSRF protection, we'll first need to make sure we use the proper HTTP methods for anything that modifies the state (PATCH, POST, PUT, and DELETE – not GET).
CSRF protection with Spring CookieCsrfTokenRepository works as follows:
The client makes a GET request to Server (Spring Boot Backend), e.g. request for the main page
Spring sends the response for GET request along with Set-cookie header which contains securely generated XSRF Token
The browser sets the cookie with XSRF Token
While sending a state-changing request (e.g. POST) the client (might be angular) copies the cookie value to the HTTP request header
The request is sent with both header and cookie (browser attaches the cookie automatically)
Spring compares the header and the cookie values, if they are the same the request is accepted, otherwise, 403 is returned to the client
The method withHttpOnlyFalse allows angular to read XSRF cookie. Make sure that Angular makes XHR request with withCreddentials flag set to true.
For more details, you may explore the following
Will Spring Security CSRF Token Repository Cookies Work for all Ajax Requests Automatically?
AJAX request with Spring Security gives 403 Forbidden
Basic CSRF Attack Simulation & Protection with Spring Security
Updated method configure(HttpSecurity http)
http
.csrf()
.ignoringAntMatchers("endpoint-to-be-ignored-for-csrf")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests()
.antMatchers("/index").permitAll()
.anyRequest().authenticated();
Endpoint specified in antMatchers with permitAll() should not required authentication and antMatchers("/index").permitAll() should work fine.
Make sure your security configuration class is annotated with #EnableWebSecurity and #EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
The security configuration class is in follows the package structure and scanned by Spring. spring-component-scanning
You may find the minimal working example here
SecurityConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// https://stackoverflow.com/a/56389047/10961238 -> WebSecurity vs HttpSecurity
// Add this method if .antMatchers("/index").permitAll() does not work
#Override
public void configure(WebSecurity web) throws Exception {
web.debug(true);
// web
// .ignoring()
// .antMatchers("/index");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/index").permitAll() //commenting this line will be results in 403
.anyRequest().authenticated();
}
}
SampleController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#Controller("myController")
public class SampleController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("::::::::::::::::::::::::::::::::Controller:::::::::::::::::::::::::::::::::");
response.getWriter().print("Hello world!");
return null;
}
}
MainApplication.java
import com.example.mappings.controller.SampleController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import java.util.Properties;
#SpringBootApplication
public class MappingsApplication {
public static void main(String[] args) {
SpringApplication.run(MappingsApplication.class, args);
}
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
System.out.println("::::::::::::::::::::::::::::::::SimpleUrlHandlerMapping:::::::::::::::::::::::::::::::::");
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MAX_VALUE - 2);
Properties urlProperties = new Properties();
urlProperties.put("/index", sampleController());
mapping.setMappings(urlProperties);
return mapping;
}
#Bean
public SampleController sampleController() {
System.out.println("::::::::::::::::::::::::::::::::Setting SampleController:::::::::::::::::::::::::::::::::");
return new SampleController();
}
}
application.properties
spring.security.user.name = user
spring.security.user.password = user
spring.security.user.roles = ADMIN
I have a controller and POJO that I want to test. The GET to the REST interface forces a login and returns a principal object and so all is good. I was able to extend WebSecurityConfigurerAdapter to enable and username and password for testing.
However, during testing, the Spring framework requires a CSRF token for a POST request. Since I have no UI and I am only testing the REST interface I want to disable it temporarily.
So I extended WebSecurityConfigurerAdapter as per the documentation:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
However this disabled the authentication. My controller receives a Principal object that is null. Here is my controller:
import java.security.Principal;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.neutech.model.ShoppingCart;
#Scope("session")
#RestController
#RequestMapping("/cart/api/v1")
public class SomeController {
#RequestMapping(value = "/thing", method = RequestMethod.POST)
public void create(#RequestBody String stuff,#AuthenticationPrincipal Principal user) {
// do stuff
}
I have tried various flavours of setting CSRF for specific URLs or HTTP verbs. All with the same result. The principal delivered to the controller is null.
After scouring the net for some kind of resolution to this I can come up with nothing. There are lots of examples tell me to do exactly what I am doing. However I only find only other similar type questions.
Can someone explain to me what I am doing wrong?
In order to enable authentication change your configure method, try this:
http
.csrf().disable()
.authorizeRequests()
.anyRequest()
.fullyAuthenticated();
If you use Spring Boot 1.5, you could disable CSRF by properties, see
Spring Boot Reference Guide:
security.enable-csrf=false # Enable Cross Site Request Forgery support.
If you use Spring Boot 2.0, you have to write a complete Spring Security configuration, see Spring Boot Security 2.0:
Custom Security
If you want to configure custom security for your application, you will need to add a WebSecurityConfigurerAdapter that adds all the bits that you want to configure. In order to avoid ordering issues with the WebSecurityConfigurerAdapter, Spring Boot auto-configuration will back off completely.
Example:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.csrf().disable()
}
}
I created a simple Spring Boot/ JS App. In a next step I tried to implement an usermanagement feature to handle multiple users.
So I implemented a usermodel and controller and secured all rest-api calls via authentication of spring security.
#Configuration
#EnableWebSecurity
#ComponentScan("package.packagename")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception{
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email, password, active from accounts where email=?")
.authoritiesByUsernameQuery("select email, role from account_roles where email=?");
}
#Override
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().permitAll()
.and()
.authorizeRequests()
.antMatchers("/index.html", "/").permitAll()
.anyRequest().authenticated()
.and()
.logout();
}
}
Additionally to this file I have the SecurityWebApplicationInitializer
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfig.class);
}
}
My problem now is the fact, that if I start the application and try to access it via localhost:8080 I face an 404 Error.
Usually the app should work even without login and it seems that with springsecurity enabled the app is not able to load the js stuff in resources/public directory.
Reading the logs showed the following:
No mapping found for HTTP request with URI [/] in DispatcherServlet with name 'dispatcherServlet'
If I start the App without spring security it works without any problems.
The securing of the api-calls works like a charm - I'm able to login, receive a cookie and use this cookie to authenticate against the api-functions which are secured by springsecurity.
I hope you can help me to resolve my (hopefully small) problem.
Thanks in advance
When you use .formLogin() you need to define the login page or use .httpBasic() auth. So you can use something like this:
.formLogin()
.and()
.httpBasic();
or
.formLogin()
.loginPage("/login.html")
You can read more here
http://docs.spring.io/spring-security/site/docs/3.2.x/guides/form.html
http://www.baeldung.com/spring-security-login
I figured out that I have to add a WebConfig.java class like this:
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfig extends WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter {
}
Now Spring is able to resolve the / call properly. I just have to make sure to open the access to all files in public for all users (permitall() function).
Anyway thanks for your help :-)
Am using spring-data-rest for developing my API and I have to use spring security to authenticate a request. When I pass a authentication details, I have to generate an API+secret key and store it in client side and sent with all further requests from that subject. And have to check it in every request and if they logout I have to regenerate key when they login again. I have implemented security as like this,
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.withUser("test").password("test").roles("test");
}
#Override protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/**").hasRole("test")
.anyRequest().anonymous()
.and()
.httpBasic()
.and()
.csrf()
.disable();
}
}
and registered filter via java config.
and I have look at this tutorial which is exactly the same am looking for. I am not good with spring and so I need to know whether am moving correctly.
Am going to implement facebook login and no registration in my site, everyone will login with facebook to access site or my app. So i wont have password too. Guide me in a proper way that how I could progress to achieve this. Thanks in advance.