I have a spring boot application, with Oauth authentication and a resource server as well in one single application. I have my frontend on a separate server, from a separate location. My frontend application doesn't seem to proceed the preflight operation to the backend, which always responds with 401. My configuration looks as the follows:
// ... annotations
public class OAuthConfig extends WebSecurityConfigurerAdapter {
// ... authencication providers
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/*.html", "layout/**", "/js/**", "/css/**", "/images/**", "/font/**",
"/signup", "/register",
"/oauth/**")
.permitAll()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/**").permitAll()
;
// #formatter:on
}
// ... beans
}
Note that I had to add exceptions for the static content as well, since it doesn't seemd to work other way, despite any documentations.
// ... annotations
public class MvcConfig extends WebMvcConfigurerAdapter {
// ... resource resolver, view resolver
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
I have tried to specify more explicitly, but nothing succeeded as well:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**").allowedMethods("GET","POST","OPTIONS","DELETE","UPDATE");
registry.addMapping("/register");
registry.addMapping("/signup");
registry.addMapping("/oauth/**").allowedMethods("GET","POST","OPTIONS");
}
//... annotations
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
// ... resource id config
#Override
public void configure(HttpSecurity http) throws Exception {
//#formatter:off
http
.anonymous().disable()
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
//#formatter:on
}
}
At this point I can't figure out if I have missed anything important to configure, to achieve CORS over the authentication endpoint (as well as the other parts of API endpoints)
If you got an HTTP 401 error, for me it doesn't mean CORS configuration is the problem. 401 is supposed to mean unauthorized, so the problem may be more in your security configuration. If it was a cross origin problem, you would have an error like "No 'Access-Control-Allow-Origin' header is present on the requested resource.".
As a matter of fact I have one of my application which got a HTTP 200 (OK) on a request that fails because of a cross origin problem.
And if you want help you should really provide details on the request/response where you got the 401 error code.
I know it's not a real answer but I don't have the reputation to comment yet, so I hope this will help.
You can also configure CORS on server. Which will work for all APIs of your application. Or you to set 'Access-Control-Allow-Origin to *' in your resquest and response so that your api can give response to any request from any server.
Related
I am writing a Java Spring Boot application that incorporates the Spring Boot Security in my pom.xml. However, It works when I redirect from login to my /home. Though when I change the page again or do a simple ajax call, I get passed a 403 error. I believe it has to do with the security and that page not having the proper access. I am looking for the best way to solve this with still keep my security intake.
Java Security:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.formLogin()
.successHandler(new CustomAuthenticationSuccessHandler()) // On authentication success custom handler
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
}
Java Success Handler:
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
String principal = authentication.getName();
System.out.println("Successful login: principal " + principal);
ADID = principal;
response.sendRedirect("/dashboard");
}
Error in Controller:
Error 403 : http://localhost:8080/edit/ajax/doesSomething
So the /dashboard is the first page I get to if the login is successful, then after that the client inputs some fields and is moved to another page that calls a different URL path. It fails I assume when it calls the other paths that are not /dashboard
Your problem is CSRF token. You can disable it in the security configure but it is better you use it. See this site for more information.
Try this ...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().permitAll()
.and()
.formLogin()
.successHandler(new CustomAuthenticationSuccessHandler())
.and()
.logout().logoutRequestMatcher(new
AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
}
or disable CSRF as quick fix.
http.csrf().disable();
Add this in java security. This will permit requests to any endpoint or specified ones:
`
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/**").antMatchers("/example/endpoint");
}
`
And you can also keep your
protected void configure(HttpSecurity http) throws Exception
I'd like my spring boot application to serve a protected frontend, as well as being an API resource server for said frontend at the same time, but I can't get the oauth stuff working.
What I want is the spring boot application to return a 302 redirect to the oauth server (gitlab in my case) when the browser requests the index.html without a token, so the user is sent to the login form. But I also want that the API to return a 401 when the API is called without a token, as I think a 302 redirect to a login page is not very useful there.
In pseudo code:
if document_url == /index.html and token not valid
return 302 https//gitlab/loginpage
if document_url == /api/restcall and token not valid
return 401
server document_url
I am working with spring boot 2.1, regarding oauth my pom.xml contains
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
This is my naive try in the SecurityConfig
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/index.html").authenticated()
.and()
.oauth2Login().loginPage("/oauth2/authorization/gitlab")
.and()
.authorizeRequests().antMatchers("/api/restcall").authenticated()
.and()
.oauth2ResourceServer().jwt();
}
}
Both configurations (oauth2Login and oauth2ResourceServer) work fine for themself. But as soon as I combine them the last one wins (so in the above example there would be no 302 and the browser would also see a 401 for the index.html). I presume they share some configuration objects so the last write wins.
Is there an (easy) way to get what I want? I know spring can do almost anything, but I would very much not to end up manually configuring a gazillion beans ...
Update:
I've made a minimal example (including #dur's suggestion) of my code here
You need to create multiple configurations and restrict them only to specific URL patterns using requestMatcher. Based on your example, your configurations should look like this:
SecurityConfigHTML
public class SecurityConfigHTML extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/index.html")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2Login().loginPage("/oauth2/authorization/gitlab");
}
}
SecurityConfigAPI
public class SecurityConfigAPI extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/api/call")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
}
}
SecurityConfigHTML
I think we should include /oauth2/** into the request matchers, otherwise the oauth2Login will not work.
404 http://localhost:8080/oauth2/authorization/gitlab
public class SecurityConfigHTML extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.requestMatchers().antMatchers("/index.html", "/oauth2/**")
.and()
.authorizeRequests()
.antMatchers("/oauth2/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
// #formatter:on
}
}
I'm trying to use spring security to secure a rest/stateless api using JWT tokens. From the research I've been seeing, it involves turning off the spring security session management and then adding some custom filters to handle the user logging in as well as checking for the jwt token.
The problem I'm having is that once i add a filter, it's run on every instead of just the endpoints I want it on. I need to open up the login endpoint as well as a few others that will facilitate enrollment and reference data that doesn't need to be secured.
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/user").permitAll()
.anyRequest().authenticated().and()
.addFilterBefore(new StatelessAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
;
}
}
All StatelessAuthenticationFilter does is print "in here". I'm only expecting to see that message print when you go to localhost:8080/api/order, but i see it show up when you go to localhost:8080/api/user.
Is there a way to get this behavior?
The way you configured, the HttpSecurity will be applied to all the URLs including the user endpoint.
authorizeRequests() .antMatchers("/api/user").permitAll() line won't prevent "user" endpoint from authentication filter being called.
It just says that any authenticated user can call it.
You need to apply the filter to "order" endpoint only. Like this:
http .requestMatchers().antMatchers("/api/user") .and() .authorizeRequests().
#tsolakp's answer sorta works for me. I ended up overriding the
configure(Websecurity) method though
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/user");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated().and()
.addFilterBefore(new StatelessAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
;
}
I'm working with Spring Boot 1.4.2.RELEASE, Spring Security 4.1.3.RELEASE, and Java 8.
For the security configuration I have the following class:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**", "/logout", "/login");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement() // 1
.sessionFixation() // 2
.migrateSession() // 3
.maximumSessions(1) // 4
.maxSessionsPreventsLogin(true).expiredUrl("/login").and() // 5
.invalidSessionUrl("/login") // 6
.and() // 7
.authorizeRequests()
.antMatchers("/app/**").authenticated()
.antMatchers("/about").permitAll()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/login").permitAll()
.loginProcessingUrl("/auth").permitAll()
.defaultSuccessUrl("/app/index", true)
.failureUrl("/login?error")
.usernameParameter("uid")
.passwordParameter("pwd").and()
.logout()
.permitAll()
.invalidateHttpSession(true)
.logoutUrl("/logout").permitAll()
.logoutSuccessUrl("/login").permitAll()
.clearAuthentication(true).and()
.exceptionHandling().and()
.csrf().disable()
.headers().frameOptions().disable()
.cacheControl().and();
}
}
When try access to "/about" (permit all everyone), redirects me to "/login". I try it a second time and now it allows me to access "/about".
I have changed the authorization order of requests in the configuration class but don't works. When I delete the lines of sessionManagement (1 to 7), everything works normally.
Do I need any extra configuration?
When you are testing this, did you clear your browser's cookie with regard to your testing site? The session management filter sets a jsessionid cookie, which gets sent back. Your browser has no idea that you reset your server, so thinks the cookie is just fine, and you send back an invalid session.
You may want to take a look at your session creation policies to see whether or not it suits your purpose.
I have below configuration class where I would like to authorize certain requests and deny all others.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/phx-config-rest/dev/master").hasRole("DEV")
.anyRequest().authenticated()
.and()
.csrf()
.disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("devuser")
.password("dev")
.roles("DEV");
}
}
As per this code my impression was, Spring will only allow me to access /phx-config-rest/dev/master using the user 'devuser' and If I try access /phx-config-rest/prod/master or any other url, request would considered as un-authorized access. BTW, this code piece is regarding Spring cloud config server. Any thought?
change the
.anyRequest().authenticated()
to
.anyRequest().denyAll()
You restrict only URL /phx-config-rest/dev/master to users with role DEV, but all other URLs are accessible for every logged in user (including user devuser) with any role,
see ExpressionUrlAuthorizationConfigurer.AuthorizedUrl#authenticated:
Specify that URLs are allowed by any authenticated user.
You have to use ExpressionUrlAuthorizationConfigurer.AuthorizedUrl#denyAll instead of authenticated:
Specify that URLs are not allowed by anyone.