(window.webpackJsonp=window.webpackJsonp||[]).push([[184],{608:function(t,e,a){"use strict";a.r(e);var n=a(56),i=Object(n.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"reactive-x-509-authentication"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#reactive-x-509-authentication"}},[t._v("#")]),t._v(" Reactive X.509 Authentication")]),t._v(" "),a("p",[t._v("Similar to "),a("RouterLink",{attrs:{to:"/servlet/authentication/x509.html#servlet-x509"}},[t._v("Servlet X.509 authentication")]),t._v(", reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client.")],1),t._v(" "),a("p",[t._v("Below is an example of a reactive x509 security configuration:")]),t._v(" "),a("p",[t._v("Java")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("@Bean\npublic SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {\n\thttp\n\t\t.x509(withDefaults())\n\t\t.authorizeExchange(exchanges -> exchanges\n\t\t .anyExchange().permitAll()\n\t\t);\n\treturn http.build();\n}\n")])])]),a("p",[t._v("Kotlin")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("@Bean\nfun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {\n return http {\n x509 { }\n authorizeExchange {\n authorize(anyExchange, authenticated)\n }\n }\n}\n")])])]),a("p",[t._v("In the configuration above, when neither "),a("code",[t._v("principalExtractor")]),t._v(" nor "),a("code",[t._v("authenticationManager")]),t._v(" is provided defaults will be used. The default principal extractor is "),a("code",[t._v("SubjectDnX509PrincipalExtractor")]),t._v(" which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is "),a("code",[t._v("ReactivePreAuthenticatedAuthenticationManager")]),t._v(" which performs user account validation, checking that user account with a name extracted by "),a("code",[t._v("principalExtractor")]),t._v(" exists and it is not locked, disabled, or expired.")]),t._v(" "),a("p",[t._v("The next example demonstrates how these defaults can be overridden.")]),t._v(" "),a("p",[t._v("Java")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v('@Bean\npublic SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {\n\tSubjectDnX509PrincipalExtractor principalExtractor =\n\t new SubjectDnX509PrincipalExtractor();\n\n\tprincipalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)");\n\n\tReactiveAuthenticationManager authenticationManager = authentication -> {\n\t\tauthentication.setAuthenticated("Trusted Org Unit".equals(authentication.getName()));\n\t\treturn Mono.just(authentication);\n\t};\n\n\thttp\n\t\t.x509(x509 -> x509\n\t\t .principalExtractor(principalExtractor)\n\t\t .authenticationManager(authenticationManager)\n\t\t)\n\t\t.authorizeExchange(exchanges -> exchanges\n\t\t .anyExchange().authenticated()\n\t\t);\n\treturn http.build();\n}\n')])])]),a("p",[t._v("Kotlin")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v('@Bean\nfun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain? {\n val customPrincipalExtractor = SubjectDnX509PrincipalExtractor()\n customPrincipalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)")\n val customAuthenticationManager = ReactiveAuthenticationManager { authentication: Authentication ->\n authentication.isAuthenticated = "Trusted Org Unit" == authentication.name\n Mono.just(authentication)\n }\n return http {\n x509 {\n principalExtractor = customPrincipalExtractor\n authenticationManager = customAuthenticationManager\n }\n authorizeExchange {\n authorize(anyExchange, authenticated)\n }\n }\n}\n')])])]),a("p",[t._v("In this example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using "),a("code",[t._v("ReactiveUserDetailsService")]),t._v(' is not performed at all. Instead, if the provided certificate issued to an OU named "Trusted Org Unit", a request will be authenticated.')]),t._v(" "),a("p",[t._v("For an example of configuring Netty and "),a("code",[t._v("WebClient")]),t._v(" or "),a("code",[t._v("curl")]),t._v(" command-line tool to use mutual TLS and enable X.509 authentication, please refer to "),a("a",{attrs:{href:"https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509"),a("OutboundLink")],1),t._v(".")])])}),[],!1,null,null,null);e.default=i.exports}}]);