CoderFunda
  • Home
  • About us
    • Contact Us
    • Disclaimer
    • Privacy Policy
    • About us
  • Home
  • Php
  • HTML
  • CSS
  • JavaScript
    • JavaScript
    • Jquery
    • JqueryUI
    • Stock
  • SQL
  • Vue.Js
  • Python
  • Wordpress
  • C++
    • C++
    • C
  • Laravel
    • Laravel
      • Overview
      • Namespaces
      • Middleware
      • Routing
      • Configuration
      • Application Structure
      • Installation
    • Overview
  • DBMS
    • DBMS
      • PL/SQL
      • SQLite
      • MongoDB
      • Cassandra
      • MySQL
      • Oracle
      • CouchDB
      • Neo4j
      • DB2
      • Quiz
    • Overview
  • Entertainment
    • TV Series Update
    • Movie Review
    • Movie Review
  • More
    • Vue. Js
    • Php Question
    • Php Interview Question
    • Laravel Interview Question
    • SQL Interview Question
    • IAS Interview Question
    • PCS Interview Question
    • Technology
    • Other

09 March, 2024

Spring Security not working after API migration to Spring Boot 3

 Programing Coderfunda     March 09, 2024     No comments   

Software versions



* Spring Boot and dependencies: 3.2.2

* Spring Core : 6.1.3

* Spring Security 6.2.1

* Jetty Server: 11.0.20

* Languages: Java 17, Kotlin (Jetbrains Kotlin and Kotlin test library versions) 1.8.10






Below are modified code snippets for Jetty based Http Server Configuration, API Configuration and API Security Configuration which now uses a SecurityFilterChain instead of WebSecurityConfigurerAdapter.


Http Server Configuration
@Configuration
@EnableConfigurationProperties(ApiServiceProperties::class)
@ComponentScan("com......service")
@Import(value = [ApiSecurityConfig::class, WebFluxConfig::class])
class HttpServerConfig(var apiServiceProperties: ApiServiceProperties) {

/**
* Jetty Server Bean.
*/
@Bean
@SuppressWarnings("LongMethod")
fun jettyServer(
context: ApplicationContext,
springSecurityFilterChain: Filter,
mdcSetterFilter: MdcSetterFilter,
webContextFilter: WebContextFilter
): Server {
LOG.info(
"Starting Jetty server with " + ""
)

.. code removed ..

ServletContextHandler(server, "").apply {
val servlet = JettyHttpHandlerAdapter(WebHttpHandlerBuilder.applicationContext(context).build())
addServlet(ServletHolder(servlet), "/")

addFilter(FilterHolder(mdcSetterFilter), "/*", EnumSet.of(DispatcherType.REQUEST))
addFilter(FilterHolder(webContextFilter), "/*", EnumSet.of(DispatcherType.REQUEST))

// The ping endpoint should be unsecured, therefore ignored by the security filter
addFilter(
FilterHolder { request: ServletRequest, response: ServletResponse, chain: FilterChain ->
if (request is HttpServletRequest && request.requestURI != "/v1/ping") {
springSecurityFilterChain.doFilter(request, response, chain)
} else {
chain.doFilter(request, response)
}
},
"/v1/*",
EnumSet.of(DispatcherType.REQUEST)
)
}.start()

.. code removed ..

server.start()

LOG.info("Started Jetty server.")
return server
}

.. code removed ..
}



API Configuration
@Configuration
@ComponentScan(basePackages = [
"com......security",
"com......service"
])
@EnableConfigurationProperties(ApiServiceProperties::class)
@Import(HttpServerConfig::class)
class ApiServiceConfig : AbstractSpringBasedApplicationConfig()



API Security Configuration
@Configuration
@EnableWebSecurity
@ComponentScan("com......security", "com......service")
@EnableMethodSecurity(prePostEnabled = false, jsr250Enabled = true)
class ApiSecurityConfig(
private val restAuthenticationEntryPoint: RestAuthenticationEntryPoint,
private val restAuthenticationProvider: RestAuthenticationProvider
) {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http
.cors { }
.anonymous { it.disable() }
.httpBasic { it.disable() }
.formLogin { it.disable() }
.logout { it.disable() }
.csrf { it.disable() }
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.exceptionHandling { it.authenticationEntryPoint(restAuthenticationEntryPoint) }
.authenticationManager { authentication -> restAuthenticationProvider.authenticate(authentication) }
.addFilterBefore(RestAuthenticationTokenFilter(), AnonymousAuthenticationFilter::class.java)
.authorizeHttpRequests { it.requestMatchers("/**").permitAll().anyRequest().authenticated() }
return http.build()
}

@Bean
fun corsConfigurationSource(): CorsConfigurationSource = UrlBasedCorsConfigurationSource().apply {
registerCorsConfiguration(
"/**",
CorsConfiguration().applyPermitDefaultValues().apply {
allowedMethods = listOf("POST", "GET", "PUT", "DELETE", "HEAD")
}
)
}
}



Custom authentication provider
@Component
class RestAuthenticationProvider(
private val securityServiceClient: SecurityServiceClient,
private val cryptoService: CryptoService
) : AuthenticationProvider {

/**
* Given a [token] and [verifiedTokenModel], return a new User with granted authorities.
*/
private fun createAuthenticatedUser(token: String, verifiedTokenModel: VerifiedTokenModel) = User
.withUsername(verifiedTokenModel.verifiedPrincipalModel.id)
.password(token)
.authorities(verifiedTokenModel.verifiedPrincipalModel.scopes.map { scope ->
SimpleGrantedAuthority("ROLE_${scope.toUpperCase()}")
})
.build()

/**
* Given a [verifiedTokenModel], create a JSON Web Token to represent the authorizations of the verified principal.
*/
private fun createJwt(verifiedTokenModel: VerifiedTokenModel) = cryptoService.createAuthToken(
.. code removed ..
)

override fun authenticate(authentication: Authentication): Authentication? =
(authentication as? RestAuthenticationToken)?.token?.let { token ->
try {
val verifiedTokenModel = securityServiceClient.verifyToken(token)
val user = createAuthenticatedUser(token = token, verifiedTokenModel = verifiedTokenModel)

RestAuthenticationToken(
.. code removed ..
jwt = createJwt(verifiedTokenModel = verifiedTokenModel)
)
} catch (e: ReplyException) {
.. code removed ..
}
}

.. code removed ..
}



Below is a comparison of the new and old code for security configuration (Spring Boot 2.6.2 and Spring Core 5.3.14)





Postman request always receives a 403 response





Logs (without permit all)
DEBUG c.a.e.d.api.v1.security.MdcSetterFilter : Setting MDC logging context.
DEBUG c.a.e.d.a.v1.security.WebContextFilter : Setting WebContext on message
DEBUG o.s.security.web.FilterChainProxy : Securing GET /v1/clients/*/brands
INFO c.a.e.d.api.v1.config.HttpServerConfig : Token ::
DEBUG o.s.s.w.access.AccessDeniedHandlerImpl : Responding with 403 status code



I also tried passing it.requestMatchers("/**").permitAll().anyRequest().authenticated() in the call to authorizeHttpRequests() however that results in a different failure behavior


Logs (with permit all)
DEBUG c.a.e.d.api.v1.security.MdcSetterFilter : Setting MDC logging context.
DEBUG c.a.e.d.a.v1.security.WebContextFilter : Setting WebContext on message
DEBUG o.s.security.web.FilterChainProxy : Securing GET /v1/clients/*/brands
INFO c.a.e.d.api.v1.config.HttpServerConfig : Token ::
...
...
DEBUG o.s.w.s.adapter.HttpWebHandlerAdapter : [49377233] HTTP GET "/v1/clients/*/brands"
...
DEBUG s.w.r.r.m.a.RequestMappingHandlerMapping: [49377233] Mapped to com......service.ClientsApiController#listBrands(String, ServerHttpRequest)
DEBUG AuthorizationManagerBeforeMethodInterceptor: Authorizing method invocation ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity com......service.ClientsApiController.listBrands(..); target is of class [com......service.ClientsApiController]

DEBUG AuthorizationManagerBeforeMethodInterceptor: Failed to authorize ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity com......service.ClientsApiController.listBrands(...); target is of class [com......service.ClientsApiController] with authorization manager org.springframework.security.config.annotation.method.configuration.DeferringObservationAuthorizationManager@2323fe6a and decision AuthorityAuthorizationDecision [granted=false, authorities=[ROLE_READ_BRANDS]]
DEBUG s.w.r.r.m.a.RequestMappingHandlerAdapter: [49377233] Using @ExceptionHandler com......service.DefaultExceptionHandler#onThrowable(Throwable, ServerWebExchange)
DEBUG o.s.w.s.adapter.HttpWebHandlerAdapter : [49377233] Completed 403 FORBIDDEN




* Have tried multiple combinations of the security chain as suggested on several similar threads

* Added a few more log statements in security configuration code to capture these events and help understand how the new flow works

* DEBUG level log statements added inside the RestAuthenticationProvider.authenticate() are not showing up in the logs, indicating it is not getting invoked, and the flow is breaking before reaching that point.






However I suspect that the configured AuthenticationProvider (tried using authenticationProvider(..) earlier, but that did not work either) and AuthenticationManager are not getting plugged in the chain for some reason. Need help from the community in guiding me to set this up correctly. Thank you.
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg
Email ThisBlogThis!Share to XShare to Facebook
Newer Post Older Post Home

0 comments:

Post a Comment

Thanks

Meta

Popular Posts

  • Write API Integrations in Laravel and PHP Projects with Saloon
    Write API Integrations in Laravel and PHP Projects with Saloon Saloon  is a Laravel/PHP package that allows you to write your API integratio...
  • Credit card validation in laravel
      Validation rules for credit card using laravel-validation-rules/credit-card package in laravel Install package laravel-validation-rules/cr...
  • iOS 17 Force Screen Rotation not working on iPAD only
    I have followed all the links on Google and StackOverFlow, unfortunately, I could not find any reliable solution Specifically for iPad devic...
  • C++ in Hindi Introduction
    C ++ का परिचय C ++ एक ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग लैंग्वेज है। C ++ को Bjarne Stroustrup द्वारा विकसित किया गया था। C ++ में आने से पह...
  • Send message via CANBus
    After some years developing for mobile devices, I've started developing for embedded devices, and I'm finding a new problem now. Th...

Categories

  • Ajax (26)
  • Bootstrap (30)
  • DBMS (42)
  • HTML (12)
  • HTML5 (45)
  • JavaScript (10)
  • Jquery (34)
  • Jquery UI (2)
  • JqueryUI (32)
  • Laravel (1017)
  • Laravel Tutorials (23)
  • Laravel-Question (6)
  • Magento (9)
  • Magento 2 (95)
  • MariaDB (1)
  • MySql Tutorial (2)
  • PHP-Interview-Questions (3)
  • Php Question (13)
  • Python (36)
  • RDBMS (13)
  • SQL Tutorial (79)
  • Vue.js Tutorial (68)
  • Wordpress (150)
  • Wordpress Theme (3)
  • codeigniter (108)
  • oops (4)
  • php (853)

Social Media Links

  • Follow on Twitter
  • Like on Facebook
  • Subscribe on Youtube
  • Follow on Instagram

Pages

  • Home
  • Contact Us
  • Privacy Policy
  • About us

Blog Archive

  • September (100)
  • August (50)
  • July (56)
  • June (46)
  • May (59)
  • April (50)
  • March (60)
  • February (42)
  • January (53)
  • December (58)
  • November (61)
  • October (39)
  • September (36)
  • August (36)
  • July (34)
  • June (34)
  • May (36)
  • April (29)
  • March (82)
  • February (1)
  • January (8)
  • December (14)
  • November (41)
  • October (13)
  • September (5)
  • August (48)
  • July (9)
  • June (6)
  • May (119)
  • April (259)
  • March (122)
  • February (368)
  • January (33)
  • October (2)
  • July (11)
  • June (29)
  • May (25)
  • April (168)
  • March (93)
  • February (60)
  • January (28)
  • December (195)
  • November (24)
  • October (40)
  • September (55)
  • August (6)
  • July (48)
  • May (2)
  • January (2)
  • July (6)
  • June (6)
  • February (17)
  • January (69)
  • December (122)
  • November (56)
  • October (92)
  • September (76)
  • August (6)

Loading...

Laravel News

Loading...

Copyright © CoderFunda | Powered by Blogger
Design by Coderfunda | Blogger Theme by Coderfunda | Distributed By Coderfunda