Skip to content

Commit c68e6ed

Browse files
eleftheriasAyush Kohli
authored and
Ayush Kohli
committed
Add remaining servlet Kotlin examples
Issue spring-projectsgh-8172
1 parent 28dff45 commit c68e6ed

File tree

15 files changed

+2695
-167
lines changed

15 files changed

+2695
-167
lines changed

docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,9 @@ This will be different in different companies, so you have to find it out yourse
196196
Before adding a Spring Security LDAP configuration to an application, it's a good idea to write a simple test using standard Java LDAP code (without Spring Security involved), and make sure you can get that to work first.
197197
For example, to authenticate a user, you could use the following code:
198198

199-
[source,java]
199+
====
200+
.Java
201+
[source,java,role="primary"]
200202
----
201203
202204
@Test
@@ -214,6 +216,22 @@ public void ldapAuthenticationIsSuccessful() throws Exception {
214216
215217
----
216218
219+
.Kotlin
220+
[source,kotlin,role="secondary"]
221+
----
222+
@Test
223+
fun ldapAuthenticationIsSuccessful() {
224+
val env = Hashtable<String, String>()
225+
env[Context.SECURITY_AUTHENTICATION] = "simple"
226+
env[Context.SECURITY_PRINCIPAL] = "cn=joe,ou=users,dc=mycompany,dc=com"
227+
env[Context.PROVIDER_URL] = "ldap://mycompany.com:389/dc=mycompany,dc=com"
228+
env[Context.SECURITY_CREDENTIALS] = "joespassword"
229+
env[Context.INITIAL_CONTEXT_FACTORY] = "com.sun.jndi.ldap.LdapCtxFactory"
230+
val ctx = InitialLdapContext(env, null)
231+
}
232+
----
233+
====
234+
217235
==== Session Management
218236

219237
Session management issues are a common source of forum questions.
@@ -498,7 +516,9 @@ To load the data from an alternative source, you must be using an explicitly dec
498516
You can't use the namespace.
499517
You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation` footnote:[The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision on what the list of returned attributes will contain.]. A very basic outline would look something like this:
500518

501-
[source,java]
519+
====
520+
.Java
521+
[source,java,role="primary"]
502522
----
503523
504524
public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@@ -526,6 +546,31 @@ You would then implement `FilterInvocationSecurityMetadataSource` to load the da
526546
527547
----
528548
549+
.Kotlin
550+
[source,kotlin,role="secondary"]
551+
----
552+
class MyFilterSecurityMetadataSource : FilterInvocationSecurityMetadataSource {
553+
override fun getAttributes(securedObject: Any): List<ConfigAttribute> {
554+
val fi = securedObject as FilterInvocation
555+
val url = fi.requestUrl
556+
val httpMethod = fi.request.method
557+
558+
// Lookup your database (or other source) using this information and populate the
559+
// list of attributes
560+
return ArrayList()
561+
}
562+
563+
override fun getAllConfigAttributes(): Collection<ConfigAttribute>? {
564+
return null
565+
}
566+
567+
override fun supports(clazz: Class<*>): Boolean {
568+
return FilterInvocation::class.java.isAssignableFrom(clazz)
569+
}
570+
}
571+
----
572+
====
573+
529574
For more information, look at the code for `DefaultFilterInvocationSecurityMetadataSource`.
530575

531576

@@ -537,7 +582,9 @@ The `DefaultLdapAuthoritiesPopulator` loads the user authorities from the LDAP d
537582

538583
To use JDBC instead, you can implement the interface yourself, using whatever SQL is appropriate for your schema:
539584

540-
[source,java]
585+
====
586+
.Java
587+
[source,java,role="primary"]
541588
----
542589
543590
public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator {
@@ -562,6 +609,28 @@ To use JDBC instead, you can implement the interface yourself, using whatever SQ
562609
563610
----
564611
612+
.Kotlin
613+
[source,kotlin,role="secondary"]
614+
----
615+
class MyAuthoritiesPopulator : LdapAuthoritiesPopulator {
616+
@Autowired
617+
lateinit var template: JdbcTemplate
618+
619+
override fun getGrantedAuthorities(userData: DirContextOperations, username: String): MutableList<GrantedAuthority?> {
620+
return template.query("select role from roles where username = ?",
621+
arrayOf(username)
622+
) { rs, _ ->
623+
/**
624+
* We're assuming here that you're using the standard convention of using the role
625+
* prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter.
626+
*/
627+
SimpleGrantedAuthority("ROLE_" + rs.getString(1))
628+
}
629+
}
630+
}
631+
----
632+
====
633+
565634
You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP using explicit Spring beans in the LDAP chapter of the reference manual.
566635
Note that you can't use the namespace for configuration in this case.
567636
You should also consult the Javadoc for the relevant classes and interfaces.
@@ -578,7 +647,9 @@ More information can be found in the https://docs.spring.io/spring/docs/3.0.x/sp
578647
Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Let's say that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter`, (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and make use of it while authenticating the user.
579648
The processor class would look like this:
580649

581-
[source,java]
650+
====
651+
.Java
652+
[source,java,role="primary"]
582653
----
583654
584655
public class CustomBeanPostProcessor implements BeanPostProcessor {
@@ -603,5 +674,25 @@ public class CustomBeanPostProcessor implements BeanPostProcessor {
603674
604675
----
605676
677+
.Kotlin
678+
[source,kotlin,role="secondary"]
679+
----
680+
class CustomBeanPostProcessor : BeanPostProcessor {
681+
override fun postProcessAfterInitialization(bean: Any, name: String): Any {
682+
if (bean is UsernamePasswordAuthenticationFilter) {
683+
println("********* Post-processing $name")
684+
bean.setAuthenticationDetailsSource(
685+
AuthenticationDetailsSource<HttpServletRequest, Any?> { context -> context.getHeader("CUSTOM_HEADER") })
686+
}
687+
return bean
688+
}
689+
690+
override fun postProcessBeforeInitialization(bean: Any, name: String?): Any {
691+
return bean
692+
}
693+
}
694+
----
695+
====
696+
606697
You would then register this bean in your application context.
607698
Spring will automatically invoke it on the beans defined in the application context.

docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,9 @@ Now that Spring Security obtains PGTs, you can use them to create proxy tickets
340340
The CAS <<samples,sample application>> contains a working example in the `ProxyTicketSampleServlet`.
341341
Example code can be found below:
342342

343-
[source,java]
343+
====
344+
.Java
345+
[source,java,role="primary"]
344346
----
345347
protected void doGet(HttpServletRequest request, HttpServletResponse response)
346348
throws ServletException, IOException {
@@ -358,6 +360,24 @@ String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8");
358360
}
359361
----
360362
363+
.Kotlin
364+
[source,kotlin,role="secondary"]
365+
----
366+
protected fun doGet(request: HttpServletRequest, response: HttpServletResponse?) {
367+
// NOTE: The CasAuthenticationToken can also be obtained using
368+
// SecurityContextHolder.getContext().getAuthentication()
369+
val token = request.userPrincipal as CasAuthenticationToken
370+
// proxyTicket could be reused to make calls to the CAS service even if the
371+
// target url differs
372+
val proxyTicket = token.assertion.principal.getProxyTicketFor(targetUrl)
373+
374+
// Make a remote call using the proxy ticket
375+
val serviceUrl: String = targetUrl + "?ticket=" + URLEncoder.encode(proxyTicket, "UTF-8")
376+
val proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8")
377+
}
378+
----
379+
====
380+
361381
[[cas-pt]]
362382
==== Proxy Ticket Authentication
363383
The `CasAuthenticationProvider` distinguishes between stateful and stateless clients.

docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ We do not intend to support non-long identifiers in Spring Security's ACL module
148148

149149
The following fragment of code shows how to create an `Acl`, or modify an existing `Acl`:
150150

151-
[source,java]
151+
====
152+
.Java
153+
[source,java,role="primary"]
152154
----
153155
// Prepare the information we'd like in our access control entry (ACE)
154156
ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44));
@@ -168,6 +170,26 @@ acl.insertAce(acl.getEntries().length, p, sid, true);
168170
aclService.updateAcl(acl);
169171
----
170172
173+
.Kotlin
174+
[source,kotlin,role="secondary"]
175+
----
176+
val oi: ObjectIdentity = ObjectIdentityImpl(Foo::class.java, 44)
177+
val sid: Sid = PrincipalSid("Samantha")
178+
val p: Permission = BasePermission.ADMINISTRATION
179+
180+
// Create or update the relevant ACL
181+
var acl: MutableAcl? = null
182+
acl = try {
183+
aclService.readAclById(oi) as MutableAcl
184+
} catch (nfe: NotFoundException) {
185+
aclService.createAcl(oi)
186+
}
187+
188+
// Now grant some permissions via an access control entry (ACE)
189+
acl!!.insertAce(acl.entries.size, p, sid, true)
190+
aclService.updateAcl(acl)
191+
----
192+
====
171193

172194

173195
In the example above, we're retrieving the ACL associated with the "Foo" domain object with identifier number 44.

0 commit comments

Comments
 (0)