Kotlin top level function not visible when used from other Maven project - maven

The following code works from within the same project:
import org.slf4j.Logger
import org.slf4j.LoggerFactory
val Any.log: Logger
get() = LoggerFactory.getLogger(this.javaClass)
Example usage:
log.info("hi!")
When I try it from another project I get a compilation error:
Cannot access 'log': it is internal in 'com.mycompany'
Why is this happening and how can I make it work?

I don't get it entirely but I've figured it out. It does work like this:
class Logger {
companion object {
val log: Logger
get() = LoggerFactory.getLogger(this.javaClass)
}
}

Related

Kotlin/Spring: Arbitrary Code Execution: Is this endpoint vulnerable to code injection?

Assume the following API endpoint controller
enum class AccessMethod {
SSO,
BASIC;
}
internal open class SomeController {
[...]
#PostMapping("{accessMethod}")
open fun trigger(#PathVariable("accessMethod", required = true) accessMethod: AccessMethod) {
logger.info {"Is arbitrary code execution possible here in spring? $accessMethod"}
}
}
I am not well aware of the validation mechanisms of Spring. Does the input get sanitised by default in the enum case a.k.a will Spring throw an error?
Malicious PoC
val malicious_payload = "\"} malicious() logger.info {\"Code Injection Successful"
client.post(endpoint_of_the_function_above + malicious_payload )
My first thought is that if the input value does not an ENUM value (string representation), it generates an error. So Enum enabled "SSO" and "BASIC" and throws everything else back.
Kotlin (like Java) is not a script language, so you can not use kotlin or java language directly for inject, because it have to build to bytecode and run on JVM. Thus, the operation cannot be manipulated.
Ofc, you can manipulate generate any query language (SQL, NoSQL or send message, etc) by which only travel through the system. Of course, the frameworks mainly handle it, but errors can always occur, right?
(Log4Shell was created because Log4J processing enabled external sources, so here it wasn't a case of code manipulated either.)
Example: improperly handled identifiers with which SQL queries are created.
I created a small project and used your "vuln" string. Just it use URL so this string converted to URL encoded.
It will say HTTP400 for any URL that is not /SSO and /BASIC. By definition, an /asdasd will also have an HTTP400 result.
\"} malicious() logger.info {\"Code Injection Successful to %5C%22%7D%20malicious%28%29%20logger.info%20%7B%5C%22Code%20Injection%20Successful
Request:
POST http://localhost:8080/%5C%22%7D%20malicious%28%29%20logger.info%20%7B%5C%22Code%20Injection%20Successful
Response:
{
"timestamp": "2022-08-25T12:51:23.092+00:00",
"path": "/%5C%22%7D%20malicious%28%29%20logger.info%20%7B%5C%22Code%20Injection%20Successful",
"status": 400,
"error": "Bad Request",
"requestId": "c3bf4acf-1"
}
Source (I mainly use the reactive environment, but this is not relevant now.)
package com.example.demo
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono
enum class AccessMethod {
SSO,
BASIC;
}
#SpringBootApplication
#RestController
class DemoApplication {
val logger: Logger = LoggerFactory.getLogger(this::class.java)
#PostMapping("{accessMethod}")
fun trigger(#PathVariable("accessMethod", required = true) accessMethod: AccessMethod): Mono<Void> {
logger.info("Is arbitrary code execution possible here in spring? $accessMethod")
return Mono.empty()
}
}
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}

Warning about config property after migrated to Quarkus 2.8.0

I have migrated an extension from quarkus 2.7.5 to quarkus 2.8.0.
After the migration, I run mvn clean install and the console shows me weird warnings about all (maybe 100) config properties (some of them are defined by me, other not like java.specification.version):
[WARNING] [io.quarkus.config] Unrecognized configuration key "my.property" was provided; it will be ignored; verify that the dependency extension for this configuration is set or that you did not make a typo
I think my integration-tests module causes this issue.
Here is my class in runtime folder:
import java.util.Optional;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
#ConfigRoot(phase = ConfigPhase.RUN_TIME, prefix="", name = "myApp")
public class MyAppConfig {
#ConfigItem(defaultValue = "defaultValue")
String firstProperty;
#ConfigItem(defaultValue = "")
Optional<String> secondProperty;
#ConfigItem(defaultValue = "defaultValue")
String thirdProperty;
// Getters ...
}
Here is my test:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
#QuarkusTest
public class MyAppIntegrationTest {
#ConfigProperty(name="myApp.first-property")
String firstProperty;
#ConfigProperty(name="myApp.second-property")
String secondProperty;
#ConfigProperty(name="myApp.third-property")
String thirdProperty;
#Test
public void testConfig() {
assertEquals("firstValue", firstProperty);
assertEquals("secondValue", secondProperty);
assertEquals("thirdValue", thirdProperty);
}
}
Can someone help me on this ? For instance, do I need a BuildItem for that ?
Thanks for your help
After spending hours on those warnings, I found that they was caused by the empty prefix field of the ConfigRoot annotation.
Setting name field to "" and prefix to "myApp" fixed the issue

How to override spring application properties in test classes? Spring’s #ContextConfiguration breaks when using Kotlin inner classes

I’m currently trying to change some Spring configuration properties in test code (they aren’t static, that’s why).
There’s this odd thing when I try to solve my problem with #ContextConfiguration(initializers = [MyTestClass.Initializer::class]).
and in MyTestClass I defined this:
inner class Initializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(applicationContext: ConfigurableApplicationContext) {
val values = TestPropertyValues.of("spring.datasource.url=" + postgresqlContainer.jdbcUrl)
values.applyTo(applicationContext)
}
}
(I’m using Testcontainers here... how to get this working might be a separate question, feel free to help me out.)
postgresqlContainer is a member of MyTestClass that I want to access. When I run the test I just get an error:
Caused by: java.lang.IllegalArgumentException: No argument provided for a required parameter: instance of fun com.example.MyTestClass.Initializer.<init>(): com.example.MyTestClass.Initializer
Huh, ok, so I kept debugging a bit and I think it’s Spring’s BeanUtils that isn’t able to handle Kotlin inner classes. If I remove the inner keyword from my inner class BeanUtils can create an instance – doesn’t help me of course, since I need access to the property of the outer class.
I wrote a little test to assert my suspicion:
import io.kotlintest.specs.StringSpec
import org.springframework.beans.BeanUtils
class Thing {
inner class InnerThing {
}
}
class BeanUtilTest: StringSpec({
"instantiate inner class" {
BeanUtils.instantiateClass(Thing.InnerThing::class.java)
// fails :-(
}
})
Question: Is there a workaround? How can I override application properties inside my test in Kotlin?
I just ran into this and, after a long time trying to figure out what was going on, I finally came up with a solution.
You can use a companion object as follows (e.g., for MySql):
#Testcontainers
#ExtendWith(SpringExtension::class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ContextConfiguration(initializers = [ExampleIntegrationTest.Companion.Initializer::class])
class ExampleIntegrationTest {
companion object {
#Container
#JvmField
val mySqlContainer = KotlinMySqlContainer()
class Initializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) {
TestPropertyValues.of(
"spring.datasource.url=" + mySqlContainer.jdbcUrl,
"spring.datasource.username=" + mySqlContainer.username,
"spring.datasource.password=" + mySqlContainer.password
).applyTo(configurableApplicationContext.environment)
}
}
}
...
}

Test service from with dependencies in spock

I am working with a kotlin and spring project, Now I am trying to do the test of some service, which has some dependencies, I am having some problems, in order to get a success test. Maybe I my design is not good enough, moreover I have problems trying to call the method from the spy object, I am getting the issue: Cannot invoke real method 'getClubhouseFor' on interface based mock object. This is my code, Could you give me any idea about what I am doing bad.
Thanks in advance!!!!
This is my code:
import com.espn.csemobile.espnapp.models.UID
import com.espn.csemobile.espnapp.models.clubhouse.*
import com.espn.csemobile.espnapp.services.clubhouse.AutomatedClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.ClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.StaticClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.contexts.ClubhouseContext
import com.espn.csemobile.espnapp.services.core.CoreService
import rx.Single
import spock.lang.Specification
class ClubhouseServiceImplTest extends Specification {
StaticClubhouseService staticClubhouseService = GroovyStub()
AutomatedClubhouseService automatedClubhouseService = GroovyStub()
CoreService coreService = GroovyStub()
ClubhouseContext clubhouseContext = GroovyMock()
Clubhouse clubHouse
ClubhouseLogo clubhouseLogo
ClubhouseService spy = GroovySpy(ClubhouseService)
void setup() {
clubhouseLogo = new ClubhouseLogo("http://www.google.com", true)
clubHouse = new Clubhouse(new UID(), "summaryType", ClubhouseType.League, new ClubhouseLayout(), "summaryName", "MLB", clubhouseLogo, "http://www.google.com", "liveSportProp",new ArrayList<Integer>(), new ArrayList<ClubhouseSection>(),new ArrayList<ClubhouseAction>(), new HashMap<String, String>())
}
def "GetClubhouseFor"() {
given:
staticClubhouseService.getClubhouseFor(clubhouseContext) >> buildClubHouseMockService()
// The idea here is to get different responses it depends on the class of call.
automatedClubhouseService.getClubhouseFor(clubhouseContext ) >> buildClubHouseMockService()
spy.getClubhouseFor(clubhouseContext) >> spy.getClubhouseFor(clubhouseContext)
when:
def actual = spy.getClubhouseFor(clubhouseContext)
then:
actual != null
}
def buildClubHouseMockService(){
return Single.just(clubHouse)
}
}
The next are the classes involved in the test:
import com.espn.csemobile.espnapp.models.clubhouse.*
import com.espn.csemobile.espnapp.services.clubhouse.contexts.ClubhouseContext
import com.espn.csemobile.espnapp.services.core.CoreService
import org.springframework.context.annotation.Primary
import org.springframework.context.annotation.ScopedProxyMode
import org.springframework.stereotype.Service
import org.springframework.web.context.annotation.RequestScope
import rx.Single
interface ClubhouseService {
fun getClubhouseFor(context: ClubhouseContext): Single<Clubhouse?>
}
#Service
#RequestScope(proxyMode = ScopedProxyMode.NO)
#Primary
class ClubhouseServiceImpl(private val clubhouseContext: ClubhouseContext,
private var staticClubhouseService: StaticClubhouseService,
private var automatedClubhouseService: AutomatedClubhouseService,
private val coreService: CoreService?): ClubhouseService {
override fun getClubhouseFor(context: ClubhouseContext): Single<Clubhouse?> {
return staticClubhouseService.getClubhouseFor(clubhouseContext).flatMap { clubhouse ->
if (clubhouse != null) return#flatMap Single.just(clubhouse)
return#flatMap automatedClubhouseService.getClubhouseFor(clubhouseContext)
}
}
}
Well, first of all GroovySpy or GroovyStub do not make sense for Java or Kotlin classes because the special features of Groovy mocks are only available for Groovy classes. So don't expect to be able to mock constructors or static methods that way, if that was the reason for the usage. This is also documented here:
When Should Groovy Mocks be Favored over Regular Mocks? Groovy mocks should be used when the code under specification is written in Groovy and some of the unique Groovy mock features are needed. When called from Java code, Groovy mocks will behave like regular mocks. Note that it isn’t necessary to use a Groovy mock merely because the code under specification and/or mocked type is written in Groovy. Unless you have a concrete reason to use a Groovy mock, prefer a regular mock.
As for your problem with the spy, you cannot use a spy on an interface type. This is documented here:
A spy is always based on a real object. Hence you must provide a class type rather than an interface type, along with any constructor arguments for the type.
So either you just switch to Mock or Stub, both of which work on interface types, or you spy on the implementation class instead. In any case, my main suggestion is to read the documentation first and then try to use a new tool like Spock. My impression is that you have not used Spock before, but of course I could be wrong.

Which dependencies are required to import `io.mockk.every` when writing Kotlin tests with Mockk?

I'm trying to write a test based on just testCompile group: 'io.mockk', name: 'mockk', version: '1.7.15' but in the code below:
import io.mockk.every
import io.mockk.any
import io.mockk.Runs
import io.mockk.impl.annotations.MockK
import io.mockk.junit5.MockKExtension
#ExtendWith(MockKExtension::class)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class ConfigDistributorTest {
#MockK
lateinit var configService: ...
#MockK
lateinit var centralisedConfigRegisterService: ...
val configDistributor = ConfigDistributor(centralisedConfigRegisterService, configService)
#Test
fun shouldDistributeConfigToComponents(){
every {
configService.readConfig(any())
} just Runs
}
}
although Runs, MockK and MockKExtension are successfully imported,
the every and any() are not available. Is io.mockk.any the correct import statement and which other dependency is required to use them?
First you need to import every. import io.mockk.every is the correct way to do it. Inside of every any is automatically imported, so you don't need to do that. Other things looks fine
Please invalidates caches, re-import project. Probably you have some issues with IDE.

Resources