Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

include spring security in example. #39

Open
xenoterracide opened this issue Apr 5, 2024 · 1 comment
Open

include spring security in example. #39

xenoterracide opened this issue Apr 5, 2024 · 1 comment

Comments

@xenoterracide
Copy link

xenoterracide commented Apr 5, 2024

I'm about 10 billion kinds of frustrated with the documentation right now. Official and especially this guide. So let's start with this guide. It doesn't include how to make it work with spring security. I know spring security isn't required for CORS, but I think it's probably at least an 80% of the time use case. This still doesn't give me proper CORS headers.

I honestly think this is beyond a problem with just documentation though... but that's a good place to start.

// © Copyright 2024 Caleb Cushing
// SPDX-License-Identifier: AGPL-3.0-or-later

package com.xenoterracide.controller.authn;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootApplication
public class ResourceServer {

  ResourceServer() {}

  public static void main(String[] args) {
    SpringApplication.run(ResourceServer.class, args);
  }

  @Bean
  SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
      .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
      .cors(Customizer.withDefaults())
      .httpBasic(c -> c.disable())
      .formLogin(f -> f.disable());
    return http.build();
  }

  @Bean
  HttpExchangeRepository httpExchangeRepository() {
    return new InMemoryHttpExchangeRepository();
  }

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
    var cors = new CorsConfiguration();
    cors.addAllowedOrigin("http://localhost:3000");
    cors.addAllowedMethod("*");
    cors.addAllowedHeader("*");
    var source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", cors);
    return source;
  }

  @Bean
  WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
      @Override
      public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/external").allowedOrigins("http://localhost:3000");
      }
    };
  }

  @RestController
  static class OidcTestController {

    private final Logger log = LogManager.getLogger(this.getClass());

    @CrossOrigin(originPatterns = "*")
    @GetMapping("/api/external")
    @NonNull
    String index(@Nullable Authentication details) {
      this.log.info("{}", details);
      var name = details != null ? details.getName() : "world";
      return "Hello, " + name;
    }
  }
}
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /api/external HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.6.0
> Accept: */*
> 
< HTTP/1.1 200 
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 12
< Date: Fri, 05 Apr 2024 10:13:21 GMT
< 
{ [12 bytes data]
* Connection #0 to host localhost left intact
Hello, world
@xenoterracide xenoterracide changed the title include spring security example. include spring security in example. Apr 5, 2024
@xenoterracide
Copy link
Author

I found out that a big part of my problem is "testing" apparently there's a hidden undocumented optimization that prevents the headers from being written if the expected headers aren't in the request. So it would be good in addition to showing the expected spring security config to include how to test it within a junit test. That would show that you need headers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant