(window.webpackJsonp=window.webpackJsonp||[]).push([[172],{596:function(e,t,n){"use strict";n.r(t);var a=n(56),o=Object(a.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"concurrency-support"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#concurrency-support"}},[e._v("#")]),e._v(" Concurrency Support")]),e._v(" "),n("p",[e._v("In most environments, Security is stored on a per "),n("code",[e._v("Thread")]),e._v(" basis.\nThis means that when work is done on a new "),n("code",[e._v("Thread")]),e._v(", the "),n("code",[e._v("SecurityContext")]),e._v(" is lost.\nSpring Security provides some infrastructure to help make this much easier for users.\nSpring Security provides low level abstractions for working with Spring Security in multi-threaded environments.\nIn fact, this is what Spring Security builds on to integration with "),n("RouterLink",{attrs:{to:"/servlet/integrations/servlet-api.html#servletapi-start-runnable"}},[e._v("AsyncContext.start(Runnable)")]),e._v(" and "),n("RouterLink",{attrs:{to:"/servlet/integrations/mvc.html#mvc-async"}},[e._v("Spring MVC Async Integration")]),e._v(".")],1),e._v(" "),n("h2",{attrs:{id:"delegatingsecuritycontextrunnable"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#delegatingsecuritycontextrunnable"}},[e._v("#")]),e._v(" DelegatingSecurityContextRunnable")]),e._v(" "),n("p",[e._v("One of the most fundamental building blocks within Spring Security’s concurrency support is the "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(".\nIt wraps a delegate "),n("code",[e._v("Runnable")]),e._v(" in order to initialize the "),n("code",[e._v("SecurityContextHolder")]),e._v(" with a specified "),n("code",[e._v("SecurityContext")]),e._v(" for the delegate.\nIt then invokes the delegate Runnable ensuring to clear the "),n("code",[e._v("SecurityContextHolder")]),e._v(" afterwards.\nThe "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(" looks something like this:")]),e._v(" "),n("p",[e._v("Java")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("public void run() {\ntry {\n\tSecurityContextHolder.setContext(securityContext);\n\tdelegate.run();\n} finally {\n\tSecurityContextHolder.clearContext();\n}\n}\n")])])]),n("p",[e._v("Kotlin")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("fun run() {\n try {\n SecurityContextHolder.setContext(securityContext)\n delegate.run()\n } finally {\n SecurityContextHolder.clearContext()\n }\n}\n")])])]),n("p",[e._v("While very simple, it makes it seamless to transfer the SecurityContext from one Thread to another.\nThis is important since, in most cases, the SecurityContextHolder acts on a per Thread basis.\nFor example, you might have used Spring Security’s "),n("RouterLink",{attrs:{to:"/servlet/appendix/namespace/method-security.html#nsa-global-method-security"}},[e._v("")]),e._v(" support to secure one of your services.\nYou can now easily transfer the "),n("code",[e._v("SecurityContext")]),e._v(" of the current "),n("code",[e._v("Thread")]),e._v(" to the "),n("code",[e._v("Thread")]),e._v(" that invokes the secured service.\nAn example of how you might do this can be found below:")],1),e._v(" "),n("p",[e._v("Java")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("Runnable originalRunnable = new Runnable() {\npublic void run() {\n\t// invoke secured service\n}\n};\n\nSecurityContext context = SecurityContextHolder.getContext();\nDelegatingSecurityContextRunnable wrappedRunnable =\n\tnew DelegatingSecurityContextRunnable(originalRunnable, context);\n\nnew Thread(wrappedRunnable).start();\n")])])]),n("p",[e._v("Kotlin")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("val originalRunnable = Runnable {\n // invoke secured service\n}\nval context: SecurityContext = SecurityContextHolder.getContext()\nval wrappedRunnable = DelegatingSecurityContextRunnable(originalRunnable, context)\n\nThread(wrappedRunnable).start()\n")])])]),n("p",[e._v("The code above performs the following steps:")]),e._v(" "),n("ul",[n("li",[n("p",[e._v("Creates a "),n("code",[e._v("Runnable")]),e._v(" that will be invoking our secured service.\nNotice that it is not aware of Spring Security")])]),e._v(" "),n("li",[n("p",[e._v("Obtains the "),n("code",[e._v("SecurityContext")]),e._v(" that we wish to use from the "),n("code",[e._v("SecurityContextHolder")]),e._v(" and initializes the "),n("code",[e._v("DelegatingSecurityContextRunnable")])])]),e._v(" "),n("li",[n("p",[e._v("Use the "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(" to create a Thread")])]),e._v(" "),n("li",[n("p",[e._v("Start the Thread we created")])])]),e._v(" "),n("p",[e._v("Since it is quite common to create a "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(" with the "),n("code",[e._v("SecurityContext")]),e._v(" from the "),n("code",[e._v("SecurityContextHolder")]),e._v(" there is a shortcut constructor for it.\nThe following code is the same as the code above:")]),e._v(" "),n("p",[e._v("Java")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("Runnable originalRunnable = new Runnable() {\npublic void run() {\n\t// invoke secured service\n}\n};\n\nDelegatingSecurityContextRunnable wrappedRunnable =\n\tnew DelegatingSecurityContextRunnable(originalRunnable);\n\nnew Thread(wrappedRunnable).start();\n")])])]),n("p",[e._v("Kotlin")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("val originalRunnable = Runnable {\n // invoke secured service\n}\n\nval wrappedRunnable = DelegatingSecurityContextRunnable(originalRunnable)\n\nThread(wrappedRunnable).start()\n")])])]),n("p",[e._v("The code we have is simple to use, but it still requires knowledge that we are using Spring Security.\nIn the next section we will take a look at how we can utilize "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(" to hide the fact that we are using Spring Security.")]),e._v(" "),n("h2",{attrs:{id:"delegatingsecuritycontextexecutor"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#delegatingsecuritycontextexecutor"}},[e._v("#")]),e._v(" DelegatingSecurityContextExecutor")]),e._v(" "),n("p",[e._v("In the previous section we found that it was easy to use the "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(", but it was not ideal since we had to be aware of Spring Security in order to use it.\nLet’s take a look at how "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(" can shield our code from any knowledge that we are using Spring Security.")]),e._v(" "),n("p",[e._v("The design of "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(" is very similar to that of "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(" except it accepts a delegate "),n("code",[e._v("Executor")]),e._v(" instead of a delegate "),n("code",[e._v("Runnable")]),e._v(".\nYou can see an example of how it might be used below:")]),e._v(" "),n("p",[e._v("Java")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('SecurityContext context = SecurityContextHolder.createEmptyContext();\nAuthentication authentication =\n\tnew UsernamePasswordAuthenticationToken("user","doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER"));\ncontext.setAuthentication(authentication);\n\nSimpleAsyncTaskExecutor delegateExecutor =\n\tnew SimpleAsyncTaskExecutor();\nDelegatingSecurityContextExecutor executor =\n\tnew DelegatingSecurityContextExecutor(delegateExecutor, context);\n\nRunnable originalRunnable = new Runnable() {\npublic void run() {\n\t// invoke secured service\n}\n};\n\nexecutor.execute(originalRunnable);\n')])])]),n("p",[e._v("Kotlin")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('val context: SecurityContext = SecurityContextHolder.createEmptyContext()\nval authentication: Authentication =\n UsernamePasswordAuthenticationToken("user", "doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER"))\ncontext.authentication = authentication\n\nval delegateExecutor = SimpleAsyncTaskExecutor()\nval executor = DelegatingSecurityContextExecutor(delegateExecutor, context)\n\nval originalRunnable = Runnable {\n // invoke secured service\n}\n\nexecutor.execute(originalRunnable)\n')])])]),n("p",[e._v("The code performs the following steps:")]),e._v(" "),n("ul",[n("li",[n("p",[e._v("Creates the "),n("code",[e._v("SecurityContext")]),e._v(" to be used for our "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(".\nNote that in this example we simply create the "),n("code",[e._v("SecurityContext")]),e._v(" by hand.\nHowever, it does not matter where or how we get the "),n("code",[e._v("SecurityContext")]),e._v(" (i.e. we could obtain it from the "),n("code",[e._v("SecurityContextHolder")]),e._v(" if we wanted).")])]),e._v(" "),n("li",[n("p",[e._v("Creates a delegateExecutor that is in charge of executing submitted "),n("code",[e._v("Runnable")]),e._v("s")])]),e._v(" "),n("li",[n("p",[e._v("Finally we create a "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(" which is in charge of wrapping any Runnable that is passed into the execute method with a "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(".\nIt then passes the wrapped Runnable to the delegateExecutor.\nIn this instance, the same "),n("code",[e._v("SecurityContext")]),e._v(" will be used for every Runnable submitted to our "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(".\nThis is nice if we are running background tasks that need to be run by a user with elevated privileges.")])]),e._v(" "),n("li",[n("p",[e._v('At this point you may be asking yourself "How does this shield my code of any knowledge of Spring Security?" Instead of creating the '),n("code",[e._v("SecurityContext")]),e._v(" and the "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(" in our own code, we can inject an already initialized instance of "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(".")])])]),e._v(" "),n("p",[e._v("Java")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("@Autowired\nprivate Executor executor; // becomes an instance of our DelegatingSecurityContextExecutor\n\npublic void submitRunnable() {\nRunnable originalRunnable = new Runnable() {\n\tpublic void run() {\n\t// invoke secured service\n\t}\n};\nexecutor.execute(originalRunnable);\n}\n")])])]),n("p",[e._v("Kotlin")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("@Autowired\nlateinit var executor: Executor // becomes an instance of our DelegatingSecurityContextExecutor\n\nfun submitRunnable() {\n val originalRunnable = Runnable {\n // invoke secured service\n }\n executor.execute(originalRunnable)\n}\n")])])]),n("p",[e._v("Now our code is unaware that the "),n("code",[e._v("SecurityContext")]),e._v(" is being propagated to the "),n("code",[e._v("Thread")]),e._v(", then the "),n("code",[e._v("originalRunnable")]),e._v(" is run, and then the "),n("code",[e._v("SecurityContextHolder")]),e._v(" is cleared out.\nIn this example, the same user is being used to run each thread.\nWhat if we wanted to use the user from "),n("code",[e._v("SecurityContextHolder")]),e._v(" at the time we invoked "),n("code",[e._v("executor.execute(Runnable)")]),e._v(" (i.e. the currently logged in user) to process "),n("code",[e._v("originalRunnable")]),e._v("?\nThis can be done by removing the "),n("code",[e._v("SecurityContext")]),e._v(" argument from our "),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(" constructor.\nFor example:")]),e._v(" "),n("p",[e._v("Java")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor();\nDelegatingSecurityContextExecutor executor =\n\tnew DelegatingSecurityContextExecutor(delegateExecutor);\n")])])]),n("p",[e._v("Kotlin")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("val delegateExecutor = SimpleAsyncTaskExecutor()\nval executor = DelegatingSecurityContextExecutor(delegateExecutor)\n")])])]),n("p",[e._v("Now anytime "),n("code",[e._v("executor.execute(Runnable)")]),e._v(" is executed the "),n("code",[e._v("SecurityContext")]),e._v(" is first obtained by the "),n("code",[e._v("SecurityContextHolder")]),e._v(" and then that "),n("code",[e._v("SecurityContext")]),e._v(" is used to create our "),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v(".\nThis means that we are running our "),n("code",[e._v("Runnable")]),e._v(" with the same user that was used to invoke the "),n("code",[e._v("executor.execute(Runnable)")]),e._v(" code.")]),e._v(" "),n("h2",{attrs:{id:"spring-security-concurrency-classes"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#spring-security-concurrency-classes"}},[e._v("#")]),e._v(" Spring Security Concurrency Classes")]),e._v(" "),n("p",[e._v("Refer to the Javadoc for additional integrations with both the Java concurrent APIs and the Spring Task abstractions.\nThey are quite self-explanatory once you understand the previous code.")]),e._v(" "),n("ul",[n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextCallable")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextExecutorService")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextRunnable")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextScheduledExecutorService")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextSchedulingTaskExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextAsyncTaskExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextTaskExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextTaskScheduler")])])])])])}),[],!1,null,null,null);t.default=o.exports}}]);