From af8226e2f0510251d88d5caf01a0e59b0640742b Mon Sep 17 00:00:00 2001 From: Silen Locatelli <88315530+SilenLoc@users.noreply.github.com> Date: Tue, 5 Mar 2024 14:08:30 +0100 Subject: [PATCH] feat: working spring workflow --- .github/workflows/springBootTest.yml | 30 +++++++++++++++++++ showcases/springboot/api_tests/hurl.env.test | 1 + .../api_tests/implemented/protected.hurl | 2 +- showcases/springboot/compose.yaml | 1 + showcases/springboot/justfile | 16 +++++----- .../com/example/hurlspringboot/Controller.kt | 2 ++ .../example/hurlspringboot/SecurityConfig.kt | 18 +++++++++-- .../src/main/resources/application.properties | 4 +-- showcases/springboot/token_creation/justfile | 20 +++++++++++++ .../springboot/token_creation/payload.json | 11 +++++++ 10 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/springBootTest.yml create mode 100644 showcases/springboot/token_creation/justfile create mode 100644 showcases/springboot/token_creation/payload.json diff --git a/.github/workflows/springBootTest.yml b/.github/workflows/springBootTest.yml new file mode 100644 index 0000000..8b94712 --- /dev/null +++ b/.github/workflows/springBootTest.yml @@ -0,0 +1,30 @@ +name: build-and-release + +on: + push: + branches: [ main ] + pull_request: + workflow_dispatch: + +env: + _JAVA_OPTS: "-Xmx2g" + GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2 -Dorg.gradle.console=plain" + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: 21 + cache: gradle + - uses: taiki-e/install-action@v2 + with: + tool: just@1,hurl@4 + - run: just verify \ No newline at end of file diff --git a/showcases/springboot/api_tests/hurl.env.test b/showcases/springboot/api_tests/hurl.env.test index 9a13b32..af77fb6 100644 --- a/showcases/springboot/api_tests/hurl.env.test +++ b/showcases/springboot/api_tests/hurl.env.test @@ -1 +1,2 @@ target=http://localhost:8000 +token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjEyMDkxMDkyOTAifQ.eyJhdWQiOlsibG9jYWwubXlfZG9tYWluLmNvbSJdLCJhenAiOiJkMTlYcDhEWEkxQVE4ZUNjeDdweHM5bkZiUTRUMHUwdCIsImVtYWlsIjoiam9obi5kb2VAb3B0cmF2aXMuY29tIiwiZXhwIjozMjUwMzY3NjQwMCwiaWF0IjowLCJpc3MiOiJodHRwczovL2F1dGgubXlfZG9tYWluLmNvbS8iLCJteV9vdGhlcl9zcGVjaWFsX2NsYWltIjoiaGVsbG8gd29ybGQiLCJuYW1lIjoiSm9obiIsInN1YiI6IjBSWHFvQ3ZzZlQ3NDludmpjIn0.TcAcntSyoXa1DMxxY8lxaOUTMcLVldrQXXM1jzAExhQ \ No newline at end of file diff --git a/showcases/springboot/api_tests/implemented/protected.hurl b/showcases/springboot/api_tests/implemented/protected.hurl index 743fd72..a0c97c6 100644 --- a/showcases/springboot/api_tests/implemented/protected.hurl +++ b/showcases/springboot/api_tests/implemented/protected.hurl @@ -1,6 +1,6 @@ # wait for healthy GET {{target}}/api/protected - +Authorization: Bearer {{token}} HTTP 200 diff --git a/showcases/springboot/compose.yaml b/showcases/springboot/compose.yaml index 3018f5b..4ac681e 100644 --- a/showcases/springboot/compose.yaml +++ b/showcases/springboot/compose.yaml @@ -2,6 +2,7 @@ services: service: image: hurlspring:latest environment: + - 'JWT_SECRET=CTRKew35ltwdWhGv9WF10lJ06oYBZKzACYhANx7QXPZpvBvCNZbq161xHg2rKhcp' - 'SERVER_PORT=8000' ports: - '8000:8000' diff --git a/showcases/springboot/justfile b/showcases/springboot/justfile index 2192b9d..553aa09 100644 --- a/showcases/springboot/justfile +++ b/showcases/springboot/justfile @@ -11,24 +11,20 @@ up c="": build docker-compose down docker-compose up {{c}} -verify: test build-and-run-api-test lint - just build-and-run-api-test +verify: test build-and-run-api-test # Run all tests test: ./gradlew test -# Run linters -lint: - ./gradlew detekt # run api tests -build-and-run-api-test: build (up "-d") api-test +build-and-run-api-test: (up "-d") api-test docker-compose down wait-for-api: - hurl api_tests/implemented/healthz.hurl --retry 60 {{hurl_opts}} + hurl api_tests/implemented/healthz.hurl --retry 60 {{hurl_opts}} --very-verbose # run acceptance tests against the running test stack @@ -43,4 +39,8 @@ api-test-not-implemented *args: wait-for-api install-hurl: curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.1.0/hurl_4.1.0_amd64.deb sudo apt update && sudo apt install ./hurl_4.1.0_amd64.deb - rm hurl_4.1.0_amd64.deb \ No newline at end of file + rm hurl_4.1.0_amd64.deb + + +@replace-token: + cd token_creation && just replace \ No newline at end of file diff --git a/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/Controller.kt b/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/Controller.kt index 16fdd67..143e912 100644 --- a/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/Controller.kt +++ b/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/Controller.kt @@ -1,3 +1,5 @@ +package com.example.hurlspringboot + import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping diff --git a/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/SecurityConfig.kt b/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/SecurityConfig.kt index 6584f5c..9f3ae38 100644 --- a/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/SecurityConfig.kt +++ b/showcases/springboot/src/main/kotlin/com/example/hurlspringboot/SecurityConfig.kt @@ -11,6 +11,10 @@ import org.springframework.security.oauth2.jwt.Jwt import org.springframework.security.web.SecurityFilterChain import org.springframework.security.oauth2.jwt.JwtDecoders; import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher +import org.springframework.security.web.util.matcher.OrRequestMatcher +import java.time.Instant +import java.util.function.Consumer @Configuration class JWTSecurityConfig { @@ -24,8 +28,8 @@ class JWTSecurityConfig { fun filterChain(http: HttpSecurity): SecurityFilterChain { return http .authorizeHttpRequests { authorizeRequests -> - authorizeRequests.requestMatchers("/api/healthz").permitAll() - .anyRequest().authenticated() + authorizeRequests.requestMatchers(unauthenticatedMatcher).permitAll() + authorizeRequests.anyRequest().authenticated() } .oauth2ResourceServer { oauth2ResourceServer: OAuth2ResourceServerConfigurer -> oauth2ResourceServer @@ -39,12 +43,20 @@ class JWTSecurityConfig { } }.build() } + + companion object { + private val unauthenticatedMatcher = OrRequestMatcher( + AntPathRequestMatcher("/api/healthz"), + ) + } } + + class LocalJwtDecoder(private val hmac256Secret: String): JwtDecoder{ override fun decode(token: String?): Jwt { val verified = JWT.require(Algorithm.HMAC256(hmac256Secret)).build().verify(token) - return Jwt.withTokenValue(verified.token).build() + return Jwt(verified.token, Instant.now(), Instant.now(), mapOf("test" to "test"), mapOf("test" to "test")) } } \ No newline at end of file diff --git a/showcases/springboot/src/main/resources/application.properties b/showcases/springboot/src/main/resources/application.properties index 1ab065d..4256a0c 100644 --- a/showcases/springboot/src/main/resources/application.properties +++ b/showcases/springboot/src/main/resources/application.properties @@ -1,3 +1,3 @@ server.port=${SERVER_PORT:#8000} -spring.security.oauth2.resourceserver.jwt.hmac256Secret=${ISSUER:#{null}} -spring.security.oauth2.resourceserver.jwt.issuer-uri=${JWT_SECRET:#{null}} \ No newline at end of file +spring.security.oauth2.resourceserver.jwt.issuer-uri=${ISSUER:#{null}} +spring.security.oauth2.resourceserver.jwt.hmac256Secret=${JWT_SECRET:#{null}} \ No newline at end of file diff --git a/showcases/springboot/token_creation/justfile b/showcases/springboot/token_creation/justfile new file mode 100644 index 0000000..d130193 --- /dev/null +++ b/showcases/springboot/token_creation/justfile @@ -0,0 +1,20 @@ + +secret := "CTRKew35ltwdWhGv9WF10lJ06oYBZKzACYhANx7QXPZpvBvCNZbq161xHg2rKhcp" + +@create-token secret=secret: + jwt encode --kid "1209109290" --secret={{secret}} "$(cat payload.json)" + +@raw: + just create-token + +replace: + just replace-token $( just raw ) + +replace-token token: + sed -i~ '/^token=/s/=.*/={{token}}/' ./../api_tests/hurl.env.test + +token choose="": + just create-token | jwt decode - -j | jq .payload"{{choose}}" + +install-dev-tools: + cargo install jwt-cli diff --git a/showcases/springboot/token_creation/payload.json b/showcases/springboot/token_creation/payload.json new file mode 100644 index 0000000..cc920ff --- /dev/null +++ b/showcases/springboot/token_creation/payload.json @@ -0,0 +1,11 @@ +{ + "my_other_special_claim": "hello world", + "email": "john.doe@optravis.com", + "name": "John", + "iss": "https://auth.my_domain.com/", + "sub": "0RXqoCvsfT749nvjc", + "aud": ["local.my_domain.com"], + "iat": 0, + "exp": 32503676400, + "azp": "d19Xp8DXI1AQ8eCcx7pxs9nFbQ4T0u0t" +}